Skip to main content

WebSocket Overview

Senticore streams market data and account events over JSON WebSocket connections. This page and the three that follow are written against the running gateway (ws_private.rs, ws_protocol.rs, public_ws_subscribe.rs) and the TypeScript SDK (SenticoreWsClient, ReliablePrivateStream). Where an older page showed op/channels frames or symbol-based market names, that protocol never shipped; the frames below are the ones the gateway accepts.

Stream families​

FamilyEndpointAuthChannels
Multiplexed publicwss://api.sentico-labs.xyz/api/v1/ws/publicnonemarketSnapshot, l2Book, trades, bbo, activeAssetCtx
Multiplexed privatewss://api.sentico-labs.xyz/api/v1/ws/private/{account} (aliases /api/v1/ws/mm/{account}, /api/v1/ws/bsl/{account})spws1… session token from POST /api/v1/ws/token, sent in an auth frame; the issuing credential needs read scope (an institutional_agent HMAC credential works, an agent key without read gets permission_denied)account, userEvents, orderUpdates, userFills, dropCopy
Snapshot + delta market feedwss://api.sentico-labs.xyz/api/v1/feed/public, redundant lines /feed/public/a and /feed/public/bnoneSequenced full-book snapshot and deltas with per-frame checksums; carries the placement status frame — see Market Feed
Server-Sent Eventshttps://api.sentico-labs.xyz/api/stream/market, …/api/stream/account/{account}none / private tokenFallback for environments without WebSocket

{account} is the 20-byte engine account in hex. Market identifiers on every channel are numeric marketId values from GET /api/v1/public/markets (items[]) or GET /api/v1/public/exchange-info, never display symbols.

The sandbox (launching — see Status) serves every family above at the same paths on api.sentico-sandbox.xyz - for example wss://api.sentico-sandbox.xyz/api/v1/ws/public. Swap the host; nothing else changes.

What every connection gets​

  • The first frames announce the stream schema and the session policy. The session frame ("event": "session") carries heartbeatMs, idleTimeoutMs, authDeadlineMs, maxSubscriptionsPerConnection, publicMaxMarketsPerConnection, reconnectPolicy and schemaId. Read those limits from the frame instead of hard-coding them.
  • Every data frame carries channel, seq and prev_seq. Sequences are namespaced: per market on public channels, and per stream domain on private channels (account snapshot vs. execution). Private execution cursors are u64 decimal strings; compare them losslessly (BigInt) and never derive a cursor for one namespace from another by ±1 arithmetic.
  • Cursor resume: subscribe with fromSeq (alias cursor, a decimal string on private channels) and the server replays what it still retains, then sends snapshot_end. A resumed orderUpdates subscription must also carry cursorNamespace: "execution-v1" (error 1004 otherwise). Outside the retention window — and routinely right after a deploy — it answers resume_required (1005) and you rebuild from REST.
  • A rotate frame before rotateByMs asks you to reconnect gracefully and includes a resubscribe journal.
  • Control frames (ack, error, warning) share the envelope of data frames.

Client responsibilities​

  • Verify continuity per channel scope: prev_seq must equal the last seq you applied (public channels are contiguous; execution channels link to the durable predecessor and can jump). On a gap, stop applying and resync.
  • Persist the last processed private seq per channel and resume from it.
  • A client Close(1000) is answered by a server close with 1000; complete the handshake instead of dropping the socket.
  • Optionally send {"method": "ping"}; the server answers with an ack on channel pong. Server heartbeats need no reply.
  • Reconnect with exponential backoff and jitter; the session frame's reconnectPolicy carries the server's base and maximum backoff.
  • Keep public market recovery separate from private account recovery.

Next​