Limits & retention
Limits & retention
Connection limits, heartbeats, slow-client behavior, feed tiers, and the event-name alias.
Connection & message limits
Heartbeats
The server sends a ping roughly every 20 seconds. Reply with a pong:
If the server does not see a pong within two heartbeat intervals, it closes the socket.
The official SDK clients reply automatically; a hand-rolled client must handle ping.
Slow-client behavior
Fan-out is concurrent with a per-send timeout, so one slow reader never blocks others. A connection that repeatedly can’t keep up (three consecutive slow or failed sends) is shed — disconnected — to protect the rest of the fleet. Read frames promptly and reconnect with backoff; the SDK clients reconnect with jittered backoff and re-subscribe for you.
Session expiry & re-auth
If you authenticated with a JWT, the server watches the token’s expiry and sends an
AUTH_EXPIRED error at exp. You have a short grace window to re-authenticate in
place with a fresh token for the same user — no reconnect needed:
The server confirms with { "type": "reauthenticated", "expires_at": … }. Changing
identity on an existing connection is rejected (AUTH_MISMATCH). API-key connections have
no per-session expiry.
Feed tiers (API-key clients)
Browser/JWT and anonymous connections reach every public market-data channel unchanged. For API-key clients, the institutional-grade channels are tier-gated:
A subscription below the required tier is rejected with TIER_NOT_ENTITLED (never
silently dropped). This gate only ever restricts API-key access; it never widens it.
Retention tiers
Which events survive for gap-recovery replay is covered in
Sequencing & replay: CRITICAL events (fills, cancels, wallet
updates, trades, market events, and everything on your user: channel) are durably
replayable; EPHEMERAL events (price ticks, order-book snapshots) are best-effort.
Event-name alias
The realtime contract is frozen, and event names are canonical. There is exactly one deprecated alias, normalized server-side so a legacy publisher can never silently drop a fill:
Always match on the canonical name (order_filled). The
WebSocket API reference lists every channel and event.

