Skip to main content

Public Channels

Public channels are unauthenticated and keyed by numeric marketId. Book levels are [price, qty] string pairs in micro-units ("1000000" = 1.0), so they survive JavaScript number limits.

Channels

ChannelScopePayload
marketSnapshotMarketThe full public snapshot: book (yes/no for outcome markets, spot for spot markets), mids, last prices, 24 h volume and reference prices, recent trades, topOfBookChecksum
l2BookMarket{ marketId, seq, prevSeq, stateVersion, topOfBookChecksum, book } — the same book object, without the surrounding statistics
tradesMarket{ marketId, seq, prevSeq, stateVersion, topOfBookChecksum, trades[] } — public trade tape without account fields
bboMarket{ marketId, seq, prevSeq, stateVersion, topOfBookChecksum, spot: { bid, ask } } for spot markets, yes/no best levels for outcome markets
activeAssetCtxMarketPer-market context (mids, last, 24 h reference); the compact companion to marketSnapshot

Private fields are stripped before public frames leave the server; the topOfBookChecksum lets you verify that your local top of book matches the server after applying a frame.

Subscribe

{ "id": "sub-1", "method": "subscribe", "subscription": { "type": "l2Book", "marketId": 3, "depth": 20 } }
{ "id": "sub-2", "method": "subscribe", "subscription": { "type": "trades", "marketId": 3, "limit": 50 } }
{ "id": "sub-3", "method": "subscribe", "subscription": { "type": "bbo", "marketId": 14 } }

The acknowledgement echoes the subscription and states snapshotSeq and liveFromSeq; the first frames after it are the snapshot, then snapshot_end, then live deltas.

Orderbook pattern

  1. Subscribe to l2Book for the market.
  2. Apply the snapshot the server sends after the ack (or fetch GET /api/v1/public/markets/{marketId}/orderbook and drop frames with seq <= snapshot seq).
  3. Apply deltas only while seq == prev_seq + 1.
  4. Compare topOfBookChecksum after each frame; on a mismatch or a gap, resubscribe with fromSeq set to the last good sequence, and if the server answers resume_required, rebuild from REST.

Placement status on the recoverable market feed

The snapshot-and-delta endpoints at /api/v1/feed/public, /api/v1/feed/public/a, and /api/v1/feed/public/b send a global status frame right after the connection's session frame and whenever order placement readiness changes:

{
"type": "status",
"sessionState": "cancel_only",
"placementReady": false,
"cancelOnlyAvailable": true,
"reason": "execution persistence degraded (1 unrecovered job(s))",
"tsMs": 1786259008273
}

This is connection state rather than sequenced market data. It has no seq, prev_seq, marketId, or channel, is not replayed, and must not take part in gap detection. Stop new placement when placementReady is false; cancelOnlyAvailable says whether cancellation still works. GET /api/v1/status remains available as a fallback after reconnects.

Limits

The session frame carries maxSubscriptionsPerConnection and publicMaxMarketsPerConnection. Exceeding either closes the connection with code 4409. Market makers that need many markets should open several connections or use the redundant /feed/public/a + /b lines, which carry every market in one sequenced stream.