Session Recovery

Session Recovery

Recover WebSocket sessions after disconnection without losing subscriptions or missing events.

Overview

Session recovery is best effort — it increases resilience but is not guaranteed. On reconnect, the server attempts to route you to the same instance that held your session, but this may not always succeed (e.g. if the instance has reached its session limit). Design your client to handle both successful recovery and fallback to a fresh session.

  1. Client sends enable_session_recovery (requires auth) — receives recovery_token + ttl_seconds
  2. Connection drops — server detaches session, preserves subscriptions, buffers incoming events for 30 seconds
  3. Client opens a new connection and sends recover_session as the very first message — do not send auth first, the recovery request includes the api_key
  4. Server replays missed messages, restores subscriptions, returns a new token

recover_session replaces the normal auth flow. If you send auth before recover_session, the connection is no longer pristine and recovery will fail.

If recovery fails (token expired, instance mismatch, buffer overflow), fall back to a fresh authsubscribe flow.

The recovery window defaults to 30 seconds after disconnect. Buffered messages are capped at 1000.

enable_session_recovery

Enable recovery on the current authenticated session.

Rate limit: 1 request per 10 seconds.

Request

{
  "type": "enable_session_recovery",
  "id": "optional-correlation-id"
}
FieldTypeRequiredDescription
type"enable_session_recovery"YesMessage type
idstring | numberNoOptional request correlation ID

Response

{
  "kind": "response",
  "type": "enable_session_recovery",
  "id": "optional-correlation-id",
  "message_id": "550e8400-e29b-41d4-a716-446655440000",
  "timestamp_ms": 1677721600000,
  "success": true,
  "recovery_token": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "ttl_seconds": 30
}
FieldTypeDescription
recovery_tokenstringUUID token for future recovery. Idempotent — returns same token if already enabled.
ttl_secondsnumberSeconds the recovery window lasts after disconnect

Errors

  • PAYLOAD_VALIDATION_ERROR — invalid payload
  • AUTHENTICATION_FAILED — not authorized
  • Rate limit exceeded

recover_session

Restore a detached session on a new connection.

Rate limit: 3 requests per 10 seconds per IP.

Preconditions: recover_session must be the first message on a fresh connection — not authorized, no subscriptions, no prior messages (seq_id must be 0). Do not send auth first.

Request

{
  "type": "recover_session",
  "recovery_token": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "last_seq_id": 42,
  "api_key": "your_api_key"
}
FieldTypeRequiredDescription
type"recover_session"YesMessage type
idstring | numberNoOptional request correlation ID
recovery_tokenstringYesUUID token from enable_session_recovery
last_seq_idintegerYesLast seq_id successfully received by the client (>= 0)
api_keystringYesThe same API key used in the original session

Response

Before the success response, the server replays all missed messages (from last_seq_id + 1 onwards) in order, each with their original seq_id. Pending snapshots are also resent.

{
  "kind": "response",
  "type": "recover_session",
  "id": "optional-correlation-id",
  "message_id": "660e8400-e29b-41d4-a716-446655440001",
  "timestamp_ms": 1677721600500,
  "success": true,
  "recovery_token": "new-token-for-next-recovery",
  "recovered_subscriptions": [
    { "channel": "orderbook_options", "query": { "instrument_name": "BTC_USDC-31OCT25-130000-C" } },
    { "channel": "trade", "query": {} }
  ],
  "last_seq_id": 55,
  "buffered_messages_count": 13
}
FieldTypeDescription
recovery_tokenstringNew token for the recovered session (old token is consumed)
recovered_subscriptionsSubscription[]All subscriptions restored from the previous session
last_seq_idnumberThe seq_id of the recovery response itself
buffered_messages_countnumberNumber of messages replayed before this response

Errors

ErrorCondition
"Cannot recover session on an already authorized connection"Connection is already authenticated
"Cannot recover session on a connection with existing subscriptions"Connection has active subscriptions
"Cannot recover session on a connection that has already exchanged messages"seq_id > 0
API_KEY_VERIFICATION_FAILEDInvalid or revoked API key
"Recovery token not found or expired"Token invalid, expired, or API key mismatch
"Recovery token is already in use"Another recovery attempt in-flight for this token
"Client last_seq_id exceeds detached session state"last_seq_id > server's detached state
"Recovery gap expired from resend cache"Missed messages no longer available
PAYLOAD_VALIDATION_ERRORMalformed request

If replay fails mid-stream, the server closes the connection with WebSocket close code 1011.

Lifecycle Example

Client A                           Server
   |                                  |
   |--- auth --->                     |
   |<--- auth success ---             |
   |--- enable_session_recovery --->  |
   |<--- { recovery_token, ttl } ---  |
   |--- subscribe orderbook --->      |
   |<--- snapshot ---                 |
   |<--- event (seq_id: 10) ---       |
   |<--- event (seq_id: 11) ---       |
   |                                  |
   X  connection drops                |
   |                                  | (server detaches, buffers events)
   |                                  |<--- event (seq_id: 12, buffered)
   |                                  |<--- event (seq_id: 13, buffered)
   |                                  |
Client B (new connection, no auth)    |
   |--- recover_session (first msg)   |
   |    { token, last_seq_id: 11 } -->|
   |                                  |
   |<--- event (seq_id: 12, replay) --|
   |<--- event (seq_id: 13, replay) --|
   |<--- recover_session success ---  |
   |    { new_token, last_seq_id: 14 }|
   |                                  |
   |<--- event (seq_id: 15, live) --- |