Skip to main content
This guide takes you from a stream key to a live, gap-free orderbook in one connection. The examples are Node.js with the ws library, but the protocol is plain JSON over a standard WebSocket, so you can use any WebSocket client.

Prerequisites

1. Connect and authenticate

Connect to:
Authentication happens during the WebSocket upgrade — there is no separate login message. Supply your key one of three ways, in order of preference:
Prefer the subprotocol or header. The ?api_key= query parameter is supported as a fallback for clients that can’t set headers, but query strings are commonly written to logs and proxies along the way — avoid it when you can.
If the key is missing or invalid, the upgrade is rejected with HTTP 401 before the connection opens. A 503 means the gateway is at capacity — reconnect, and you’ll land on fresh capacity. A 429 means your account is at its connection limit — close a connection you no longer need instead of retrying.

2. Receive welcome

Immediately after the upgrade succeeds, the server sends a welcome frame:
Keep the connectionId — quote it in any support request so we can find your session in our logs. The limits tell you how many subscriptions this connection accepts and how long it will live before the server closes it for a scheduled reconnect.

3. Subscribe

Send a subscribe frame listing the markets you want. The only required fields are type and markets; channels defaults to ["book"].
For each market in the batch you get back either a subscribed ack or an error (for example, UNKNOWN_MARKET) — one reply per market, so a single bad entry never sinks the rest of the batch.
Cache the mapping from subscriptionId to whatever local state you keep for that market — every subsequent frame for this subscription is keyed by that id, and it’s also the handle you pass to unsubscribe. snapshotPending: true tells you a snapshot is on its way.

4. Apply the stream

A book subscription delivers a snapshot first, then delta frames:
That’s the whole opening sequence. snapshot replaces your book; delta mutates it. Because of the sequencing contract, your apply loop needs no gap-handling logic of its own — if we ever could not send a contiguous delta, we send a fresh snapshot instead.

Optional: the trade tape

To also receive each fill on a market as it executes, subscribe with the trade channel (each (market, channel) pair is its own subscription, with its own subscriptionId):
Then add a case to the handler:
The tape needs no state on your side: there is no snapshot (snapshotPending: false on the ack), and frames flow from the moment you subscribe — earlier fills are not replayed. See the trade frame reference for the full semantics. The trade channel is available on Polymarket; Limitless publishes no public trade feed, so a trade subscribe there is rejected with UNSUPPORTED_CHANNEL.

5. Keep the connection healthy

  • The server sends WebSocket pings every 30 seconds; your client library answers them automatically. You can also send an application-level ping and get a pong back.
  • Watch for goodbye frames and socket closes, and reconnect. Connections are closed at the connectionTtlSeconds lifetime from welcome, so schedule a proactive reconnect before then.
  • On a status frame with state: "resyncing", drop that subscription’s local book and trust the next snapshot. See reconnect & resync handling.

Next

The WebSocket API reference documents the full wire contract, one page per concern: Authentication, Connection lifecycle, Subscriptions & markets, the Orderbook and Trades channels, Errors & status, and the full Message catalog.