Skip to main content
The user feed streams your account‑scoped updates (orders, fills, cancels).

Messages

The user feed sends each update as a bare JSON object (no tuple envelope). All updates share one envelope; the action is determined by which of unmatched / matched are populated and by origin.

Common envelope

messageID is the stream entry id added by the streaming-api before send. Persist the latest one you have processed — it is your replay cursor. See Replaying missed messages below.

How to identify the action

  • unmatched.filled === 0 && unmatched.offered > 0 -> order placed
  • unmatched.offered === 0 -> order cancelled
  • matched != null && unmatched == null -> matched as taker
  • matched != null && unmatched != null -> matched as maker (partial fill if unmatched.remaining > 0)
Updates for orders placed with orderType: "postArb" also carry isPostArb: true inside matched / unmatched (on placed, filled, and cancelled updates); the field is omitted otherwise.

Side and market semantics by bet type

The meaning of side (and which extra fields appear) inside matched / unmatched depends on type: market is only present on moneyline1x2 updates: it names the 3-way outcome the market is about (home team, away team, or the draw), and side says whether the bet is yes or no on that outcome. All fields are from your perspective — as maker you see your posted side; as taker you see the side you took.

Action: order placed

A new offer was put on the book. unmatched.filled is 0, unmatched.offered > 0, and matched is null.

Action: order cancelled

The user (or the system on their behalf) cancelled an offer. The distinguishing field is unmatched.offered === 0.

Action: order matched (taker)

The user took someone else’s offer. unmatched is null, matched carries the fill, and origin is "wager".

Action: order matched (maker, partial fill)

Someone hit the user’s posted offer. Both matched and unmatched are populated; unmatched.remaining shows what is still on the book. Because unmatched is set, origin is "offer".

Action: order matched (moneyline1x2)

Fills on 3-way soccer markets carry the market + side pair described above instead of a participant-hex side. Here the user took “yes” on the home team at +120 (a bet that Arsenal wins):
Note the two perspectives of the same fill: the taker sees side: "yes" at +120, the maker sees side: "no" at -120 on the same market.

Replaying missed messages

The v2 user feed supports gap recovery after a dropped connection. Every message carries a messageID (a monotonically increasing stream entry id, e.g. "1751552702114-0"). If your connection drops, you can fetch exactly the messages you missed.

Endpoint

Authentication is the same as the WebSocket: token in the Authorization header, Auth header, or token query parameter. Only messages belonging to the authenticated user are returned.

Response: success

Your afterID was still present in the retained history, so the returned list is a complete gap-fill — nothing between afterID and beforeID was lost:
Apply the messages in order and resume processing live messages.

Response: cache_expired

Your afterID has aged out of the retained history, so the server cannot prove the replay is complete:
availableMessages is whatever is still retained, oldest first. Messages older than the retention window are not recoverable through replay — reconnect promptly rather than relying on long look-back.

Example: reconnecting client with replay

A complete Node.js client (keepalive ping/pong omitted for brevity — see the quickstart at the top of this page). Two things keep it correct: every message — live, buffered, or replayed — passes through one forward-only cursor check, and a failed replay reconnects rather than going live over the gap.