Skip to main content
A subscription is one (market, channel) pair on a connection. You create them with subscribe, name the market with a MarketStream, and the server hands back a subscriptionId that keys every frame that follows.

MarketStream

How you reference a market on the wire. It’s a discriminated union on venue — you build it from venue-native identifiers you already have, or that you get from the Markets API.
Limitless YES and NO are two views of one shared orderbook — the NO book is the exact complement of the YES book. One slug covers both sides; you subscribe to YES and NO as two separate MarketStream entries, one per token. You can subscribe to either or both; both stream accurately.
Kalshi works differently: one ticker, one book, one subscribable side. Where Limitless gives you two entries and you pick either or both, a Kalshi ticker addresses a single YES-priced orderbook and there is no second entry to subscribe to. side accepts only "yes"; a subscribe naming "no" is refused with UNKNOWN_MARKET rather than returning a NO feed. You read the NO side by deriving it locally — see below.side: "yes" and an omitted side name the same subscription. Sending both forms on one connection does not create two: the second returns the existing subscriptionId, under the idempotency rule described in subscribe.

Deriving the NO side of a Kalshi market

The book we publish is YES-priced. The NO side is that same book read from the other end, which you compute locally. Two transforms, and you need both — applying 1 - price without swapping the sides produces a plausible book that is wrong:
  • Price becomes 1 - price.
  • Sides swap. Our asks are your NO bids; our bids are your NO asks.
  • Size carries across unchanged. One contract is one contract read from either end: buying NO at 0.47 and selling YES at 0.53 move the same single contract, so only the price coordinate and the bid/ask label flip. size is in shares, not notional, so it never scales by price.
  • Re-sort afterwards. Our bids are ordered best first (descending price) and our asks best first (ascending price), and 1 - price reverses both orderings.
Given this snapshot for { "venue": "kalshi", "ticker": "KXNBA-25-LAL" }:
the NO view is: Three checks to assert against your own implementation:
  • YES best ask 0.53 + NO best bid 0.47 = 1.00
  • YES best bid 0.52 + NO best ask 0.48 = 1.00
  • The spread is preserved: 0.01 in both views.
delta frames derive the same way, side included:
The first is what we send; the second is that same change in the NO view. size: 0 still deletes the level.

Channels

A subscription is one (market, channel) pair. Subscribing to one market on both channels counts as two subscriptions against the per-connection cap.

subscribe

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 (it is always false on the trade channel — the tape has no snapshot). Subscribing is idempotent per (connection, market, channel): a repeat returns the existing subscriptionId rather than creating a second one.

unsubscribe

Unsubscribe by the subscriptionId(s) from prior subscribed acks. One unsubscribed reply per id, carrying subscriptionId, market, and channel.

list

Returns a subscriptions frame: one atomic snapshot of every active subscription on this connection.