Skip to main content
The l2Book channel delivers a complete order book snapshot for a contract every time the book changes, rate-limited to at most one frame per 20 ms per contract. Every message includes all price levels for both bids and asks, so you can always replace your local book state in full rather than applying partial diffs. When you subscribe, the server immediately pushes the current snapshot, so you get a consistent starting state without making a separate REST call. No change is lost to the rate limit: only the newest state is kept, and a frame is emitted once the interval elapses, so the book reaches you within one interval at the latest.

Subscribing

Replace "1" with the contract ID you want to track, passed as a string. You can hold simultaneous l2Book subscriptions for multiple assets on the same connection.
string
required
The contract ID, as a string (for example "1"). Read contract IDs from configs.
integer
Optional price-grouping level, as a raw integer in the same units as tickSize and prices. It must be one of the values listed in that contract’s digitMerge array in configs. Omit it to receive the ungrouped book.
  • When group is not an integer, or is not a level configured for the contract, the subscription is rejected with BAD_SUBSCRIPTION; it does not fall back to the ungrouped book.
  • Each grouping level is an independent subscription; you can subscribe to several levels of the same contract at once.
  • Grouping rounds bid prices down and ask prices up to the level boundary, and sums sz and n within each bucket.

Push message format

The server pushes a message like the following whenever the book changes:

Field reference

int64
Frame send time in Unix milliseconds, from the server clock. Sits at the top level alongside data, and is consistent with the bbo, trades, and candle frames.
string
The contract ID this snapshot belongs to. Matches the asset value in your subscription.
number
Snapshot timestamp in Unix milliseconds. May be 0 when the exchange is in a pre-launch state.
string
Current mark price as a raw string. Returns "0" when mark price is not yet available.
string
Current oracle price as a raw string. Returns "0" when oracle price is not yet available.
int64
The price-grouping level of this frame, as a raw integer. 0 means the ungrouped book.
boolean
A JSON boolean, not a string. true means the book at this grouping level does not have enough depth to fill the maximum number of levels; false means it does.
array
A two-element array: levels[0] contains bids sorted high-to-low by price; levels[1] contains asks sorted low-to-high by price. An empty array means no orders on that side.Each element within a level array is an object with the following fields:
  • px (string) — Price of this level (raw).
  • sz (string) — Total size resting at this price (raw).
  • n (number) — Number of individual orders aggregated at this price.

Handling the initial snapshot

The server pushes the first snapshot immediately on subscribe. You can safely use this as your starting state:
1

Subscribe and receive the first snapshot

Send the subscribe message. Once the subscription is acknowledged the server pushes the current book directly to you, in exactly the same frame format as subsequent updates. A contract with no book data yet sends nothing until its first change.
2

Replace state on every subsequent message

Each subsequent push is also a full snapshot. Replace your entire local book (both sides) with the new levels — there is no need to apply diffs or maintain a patch log.
3

No deduplication needed

Every frame is a full snapshot, so applying the same frame twice is idempotent. Overwrite local state with each frame. When you subscribe with group, the initial snapshot is for that grouping level.

Handling a removed grouping level

When a contract configuration update removes a grouping level, the server pushes one GroupRemoved frame to that level’s subscription and then removes every subscription to it:
string
Always "GroupRemoved". Use this key to tell the frame apart from a book snapshot.
string
The contract ID.
int64
The grouping level that was removed.
After this frame, stop waiting for data on that subscription and subscribe to a level that is still listed in digitMerge in configs. The ungrouped book (no group) is never removed.
Use the WebSocket l2Book channel instead of polling the REST /info l2Book endpoint. You receive the initial snapshot automatically on subscribe, and every subsequent push keeps your local state current without any request overhead.
All price and size values are returned as raw strings. Apply the appropriate decimal precision for the contract when displaying values to users.