bezant
Typed async access to the Interactive Brokers Client Portal Web API — Rust-first, with HTTP / CLI / MCP / TypeScript surfaces auto-generated from the same vendored OpenAPI spec.
Bezant turns IBKR’s 154-endpoint CPAPI into five ergonomic surfaces that all ship from the same vendored OpenAPI 3.1 spec:
| Crate / package | Install | What it’s for |
|---|---|---|
bezant-core | cargo add bezant-core | Typed async Rust client. Keepalive, WebSocket streaming, pagination, symbol cache, 11 typed error variants, is_retryable() predicate, Subscription cancel handles |
bezant-server | cargo install bezant-server | axum HTTP sidecar exposing CPAPI as plain REST+JSON for any language. Production-hardened: CF Access cookie filtering, edge-cookie strip, request-ID propagation, graceful shutdown, concurrency cap |
bezant-cli | cargo install bezant-cli | bezant accounts, bezant positions DU123, bezant quote AAPL, bezant orders DU123 — --output {json,table} |
bezant-mcp | cargo install bezant-mcp | Model Context Protocol server — Claude / Cursor / Continue can call IBKR tools |
| TypeScript client | npm install from repo | Auto-generated TS client for Node / Deno / browser |
All five drive off the same vendored IBKR OpenAPI spec. Re-run
./scripts/codegen.sh when IBKR ships a new revision and every surface
updates together — verified by 14 normaliser-invariant tests + a
CI drift check.
What’s special about it
- Production-grade IBKR deploy story. Out of the box, every cloud
IBKR API client hits the same wall:
api.ibkr.com(Akamai-fronted) rejects datacenter egress IPs. bezant ships a documented Cloudflare Zero Trust + residential-Pi recipe that bypasses it without code changes — same image runs on Railway or a Pi at home with no fork. - Single-tenant proxy by design.
bezant-serveris honest about its trust model: one shared cookie jar, one IBKR account. No surprising fan-out semantics, no opaque session sharing. - Edge-aware cookie handling. Drops
CF_Authorization,CF_AppSession, AWS ALB OIDC, OAuth2 Proxy, Vercel JWT, Pomerium cookies before they reach IBKR — Akamai 401s on unrecognised cookies and we don’t want your bot to inherit that surprise. - Per-request observability. Every typed handler is
#[tracing::instrument]’d, every request gets a UUIDx-request-idechoed in the response, every mapped 4xx/5xx logs at the boundary with the typed error variant. - Diagnostic probe.
/debug/probe(token-gated) walksauth_status → ssodh_init → tickle → accountsand pins the first diverging step in a top-level verdict. Built specifically to discriminate “proxy regression” vs “upstream IBKR rejection” so you don’t waste hours debugging code that’s working.
Where to go next
| Goal | Page |
|---|---|
| Get something running locally | Quickstart |
| Understand the layered design | Architecture overview |
| Deploy to production | Cloudflare Zero Trust + Pi |
| Use the Rust crate | Rust crate |
| Use the HTTP sidecar from non-Rust | HTTP sidecar |
| Use the CLI | Command-line |
| Wire up an MCP client | MCP server |
| Refresh the spec / regen clients | Codegen pipeline |
| Contribute | Contributing |
Status
Alpha — v0.3. Production-deployed against IBKR live + paper accounts; the public API surface will continue to evolve until v1.0. See the ROADMAP for what’s shipped and what’s next.
Not affiliated with Interactive Brokers
Bezant is an independent open-source project. Trading involves substantial risk; this software is provided without warranty. See the license.