Skip to main content

Why this is safe for trading

The replay window (resumeWindowMs, e.g. 60000) is not a fragile time limit you risk losing data past — it’s the buffer for zero-loss fast resume. Recovery is a two-tier, designed failover:
  1. Within the window — reconnect and replay missed updates from your cursor with no gaps. This covers the overwhelming majority of real-world disconnects (network blips, redeploys), which resolve in seconds.
  2. Outside the window — the gateway emits snapshot_required and you restore full, current state with a single fast REST snapshot. This is an explicit, deterministic path, not an error.
The window is intentionally short because for realtime trading the right recovery for a long gap is a fresh snapshot of the current market, not a slow replay of stale prices. Worst case is one REST call — bounded and predictable, never an open-ended outage. See Reliability & Operations.

What “resume” means

After a successful login, the server returns a resume block in login_ok:
This tells you:
  • serverEpoch — identifies the current gateway session (changes on restart)
  • resumeWindowMs — how long replayable data is buffered
  • replayChannels — channels eligible for replay
  • serverEntryIds — server’s latest cursor per channel

Server-initiated reconnect on release

When we deploy a new gateway version or rebalance a node, the server does not drop you silently. It first pushes a control frame to every connected client:
This is a JSON text frame (control), sent on all receiveType modes. After sending it the server keeps streaming for a short grace window (a few seconds), then closes the socket. What your client should do:
  1. React to the message, not the socket error. As soon as you see type: "reconnect", reconnect to the same endpoint. Don’t wait for the eventual close (1006/4002) — acting on the hint minimizes your gap during a release.
  2. The replacement replica has a new serverEpoch. So resuming with your stored serverEpoch will return snapshot_required with reason server_restarted (see below). This is expected on a release — re-fetch a REST snapshot for the affected channels and continue.
Treat any reconnect frame as “reconnect now”, regardless of reason. New reasons may be added over time; the action is always the same.

What clients must persist

To resume safely, persist:
  1. serverEpoch
  2. The most recent entryId you processed per channel

entryId format

Each streamed message includes an entryId:
  • ts_ms — server timestamp (UTC, milliseconds)
  • seq — monotonic per-channel sequence
Important:
  • entryId is a cursor, not a delivery guarantee
  • Gaps are normal (upstream behavior, coalescing, backpressure)

Resume login example

On reconnect, send the same serverEpoch and your stored cursors:
If replay succeeds, the server sends:

snapshot_required (when replay is not possible)

Sometimes replay cannot be done safely. In that case the server sends:

Possible reasons

  • server_restarted — gateway restarted, cursors invalid
  • resume_window_exceeded — your cursor is older than the replay buffer
  • client_backpressure — your client couldn’t consume replay fast enough

Important nuance

Replay eligibility depends on cursor age, not disconnect duration:
A very short disconnect can still exceed the window if your last processed message is already old.

How clients should handle snapshot_required

When you receive snapshot_required:
  1. Fetch a fresh snapshot via REST for the listed channels (e.g. /fixtures, /fixtures/odds, /futures)
  2. Clear lastSeenId for those channels
  3. Continue processing live updates
The gateway continues streaming after snapshot_required. This message is your signal that local state must be rebuilt.

Python reconnect example (FULL TEMPLATE)

This example:
  • Persists serverEpoch and per-channel lastSeenId
  • Sends cursors only for replayable channels
  • Handles snapshot_required
  • Automatically reconnects on failure