Connecting
Each stream is a separate WebSocket connection at its own path; there is no subscribe/unsubscribe message protocol. Authenticated Trading API streams use the same identity as REST (details): useAuthorization: Bearer <token> and User-Id headers when your client can set them. Browser clients can pass Bearer-<token>, User-<id> as Sec-WebSocket-Protocol values.
Trading API streams support two message protocols:
- v0 (default): raw JSON payloads.
- v1: include
tplus.ws.v1inSec-WebSocket-Protocol. Messages arrive in envelopes:
/trades/user/events/{user_id}) message, for example:
data field under v1.
For authenticated browser clients, Bearer-<token>, User-<id>, and tplus.ws.v1 can appear in the Sec-WebSocket-Protocol list. The Trading API auth parser reads the bearer token and user from any position in the list, and enables v1 if tplus.ws.v1 is present. When auth succeeds through that header, the server echoes the first offered value as the selected subprotocol; put tplus.ws.v1 first when you want the browser connection to report v1 as selected.
Market Data API streams currently use raw v0 frames only: a WsWelcome text frame first, then raw payloads. Do not expect v1 envelopes from those services.
After the welcome frame, the listed OMS and MDS streams run through a shared WebSocket stream loop. That loop sends a WebSocket ping every 20 seconds and responds to WebSocket ping frames with pong frames. For one-way stream connections, a text message {"type":"ping"} can receive {"type":"pong"}. Do not use that text message as the /control heartbeat: /control parses text frames as order commands, and invalid v1 command envelopes can be rejected before app-level ping handling.
The shared stream loop does not define an application-level idle timeout. Additional idle-close policies can be enforced at a reverse proxy or load balancer.
MDS has a single concurrent-connection cap shared by all six public WebSocket routes. The top-level MDS configuration setting max_public_ws_connections defaults to 1000 per instance and takes effect on restart, independently of REST rate limiting. At capacity, MDS refuses new upgrades with HTTP 503 (SERVICE_UNAVAILABLE, retryable); existing streams continue. A connection holds its slot until its stream ends, including error and lag termination. For example, with a cap of 2, two connections across any of these routes are accepted, a third is refused, and closing either connection allows a new one. Setting the cap to 0 refuses all public WebSocket upgrades.
These market-data streams remain public and unauthenticated. The cap bounds their total count inside each MDS process; per-IP and volumetric connection limits remain the edge’s responsibility. Operators should size the cap for instance resources and expected subscribers and coordinate it with the edge connection limit.
Trading API streams (authenticated)
Settler approval delivery uses a dedicated WebSocket outside the Trading API surface (
/settlement/approvals/{settler_pubkey}, encrypted to the settler’s key); see Settlement.
Market Data API streams (public)
Indicative funding and borrow rates also stream publicly from the interest engine’s
/rates endpoint, a separate service from the two documented APIs; see Fees & rates.
Message schemas are in the live Trading API and Market Data API references.
Lag and resync
Trading API streams close with code1013 and reason resync_required when the client falls behind. On v1, the server sends a RESYNC_REQUIRED error before closing. Market Data API streams do not support v1 envelopes; if their broadcast receiver lags, the raw stream handler terminates the connection without a resync message.