Browsers can use
EventSource with withCredentials: true to send the session cookie. EventSource cannot set headers, so a bot that authenticates with Authorization: Bearer needs an SSE client that supports custom headers (for example a fetch-based reader).The streams
Futures order book
GET /fut/book-stream — public depth for one futures market.Futures market stream
GET /fut/stream/events — one market’s book plus your fills and positions in it.Futures account stream
GET /fut/stream/user — your futures fills and positions across all markets.Option board
GET /markets/board/stream — public marks, IV, and delta for one underlying.Portfolio balances
GET /portfolio/balances/stream — your balance and margin summary.book-stream and board/stream are public. The other three require a session (cookie or Authorization: Bearer) and carry only your own fills, positions, and balances.
Futures order book — public
string
required
number
Levels per side. Default
25, range 1–100.number
Emit cadence. Default
100, range 50–2000.GET /fut/book-stream — pure market data. The first event is snapshot; after that an update event is sent whenever the book changes. Every event carries the full depth-limited book, so you can replace your local book on each one. Each event has an SSE id:; a :heartbeat comment is sent after 15 seconds without changes.
Futures market stream — private
string
required
One market per connection.
number
Default
25, max 250.boolean
Restrict positions to open ones.
number
Default
500, range 100–5000.GET /fut/stream/events — Session. One market’s order book, your fills, and your positions. Events are snapshot, then delta; an error event carries { code, message, retryable }. Each event’s data is an envelope:
eventType is PerpStreamSnapshot, PerpStreamDelta, or PerpStreamError (legacy names — this is the futures stream).
object
Snapshot: the full book. Delta: only changed levels; a level with
size: "0" was removed.array
Your fills:
{ id, orderId, marketId, side, price, quantity, liquidity, createdAt }, where liquidity is maker or taker.array | object
Snapshot: your positions
{ id, marketId, side, quantity, entryPrice, realizedPnl, status, updatedAt }. Delta: { upserts, removedIds }.Futures account stream — private
GET /fut/stream/user — Session. Your fills and positions across all futures markets on one connection, with no order book. This is the stream to use for account-wide fill tracking. Params: openOnly, intervalMs (default 500, range 100–5000).
Events are snapshot, delta, and error, with eventType PerpUserStreamSnapshot, PerpUserStreamDelta, and PerpUserStreamError. Here eventSeq increases by exactly one per event, so a jump means you missed data — reconnect. A : heartbeat comment is sent after 5 seconds without events.
Option board — public
string
e.g.
SPX or NDX. Always pass it.GET /markets/board/stream — data-only messages (no event: line), each an envelope { eventId, eventType: "OptionsBoardSnapshot", eventSeq, engineTs, sourceTs, payload }. The payload is the full board, the same shape as GET /markets/board. A new snapshot is sent when the board changes — at most about once per second — with : unchanged comments in between.
eventSeq on this stream is shared across all connections and is not contiguous per client. Each message is a full board, so simply replace your local copy.bid and ask come from the OCX order book. For a single option’s full depth, poll GET /orderbook/{marketId}.
Portfolio balances — private
GET /portfolio/balances/stream — Session. event: snapshot with { type: "snapshot", payload } on connect, then event: update with { type: "update", payload } whenever your balances change. The payload matches GET /portfolio/balances. A :keepalive comment is sent every 15 seconds; event: error carries { message }.
Consumption checklist
1
Connect and snapshot
Open the stream and apply the first snapshot as your full state.
2
Fold in updates
Replace (book stream, board stream) or merge (
delta events) as described per stream; treat a level with size: "0" as removed.3
Watch for silence and gaps
Use the account stream’s contiguous
eventSeq and the heartbeat comments to detect a dead or lossy connection.4
Reconnect and re-snapshot
On any drop or gap, reconnect with backoff and rebuild from the new snapshot.