> ## Documentation Index
> Fetch the complete documentation index at: https://docs.parlayx.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Orderbook channel

> Snapshot and delta frames, price/size units, and the gap-free sequencing guarantee

The `book` channel delivers a normalized orderbook: a full `snapshot` first,
then `delta` frames carrying only the levels that changed. It's the default
channel when you omit `channels` on [`subscribe`](/streaming/subscriptions#subscribe).

## Prices and sizes

Every market is normalized to one scale, regardless of venue:

| Field   | Unit                                                           |
| ------- | -------------------------------------------------------------- |
| `price` | Implied probability, a decimal in `[0, 1]` (dollars per share) |
| `size`  | Outcome shares                                                 |

A `Level` is `{ price, size }`. A snapshot carries separate `bids` and `asks`
arrays of levels; a delta carries a flat list of `changes`, where each change
is `{ side, price, size }` and `size: 0` means that price level is now gone.

## `snapshot` and `delta`

```json theme={null}
{
  "type": "snapshot", "v": 1, "serverTimestamp": 1748020034210,
  "subscriptionId": "f47ac10b-…", "seq": 4287, "venueTimestamp": 1748020034120,
  "bids": [ { "price": 0.52, "size": 1250 } ],
  "asks": [ { "price": 0.53, "size": 800 } ],
  "status": "live"
}
```

```json theme={null}
{
  "type": "delta", "v": 1, "serverTimestamp": 1748020034260,
  "subscriptionId": "f47ac10b-…", "seq": 4288, "venueTimestamp": 1748020034250,
  "changes": [ { "side": "bid", "price": 0.52, "size": 0 } ]
}
```

A `snapshot` **replaces** your local book. A `delta` **mutates** it: each change
is `{ side, price, size }`, and `size: 0` deletes that price level. We
deliberately don't distinguish add / update / remove — it's always "set this
level to this size, where 0 means gone."

`venueTimestamp` is the venue's timestamp for the underlying event;
`serverTimestamp` is when we emitted the frame.

A minimal apply loop:

```js theme={null}
const books = new Map();        // subscriptionId -> { bids, asks }

function onSnapshot(f) {
  books.set(f.subscriptionId, { bids: f.bids, asks: f.asks });
}

function onDelta(f) {
  const book = books.get(f.subscriptionId);
  if (!book) return;
  for (const c of f.changes) {
    const side = c.side === "bid" ? book.bids : book.asks;
    const i = side.findIndex((l) => l.price === c.price);
    if (c.size === 0) { if (i >= 0) side.splice(i, 1); }
    else if (i >= 0) side[i].size = c.size;
    else side.push({ price: c.price, size: c.size });
  }
}
```

## Sequencing and resync

Per subscription, `seq` is a monotonically increasing integer that **we** assign
at ingestion (not the venue). The core guarantee for the book channel:

<Note>
  **We never send a `delta` whose `seq` is not exactly the previous `seq` + 1. If
  we otherwise would, we send a `snapshot` instead.**
</Note>

How this works:

* The first frame on a book subscription is always a `snapshot`.
* On a venue gap or upstream reconnect, you get
  [`status: resyncing`](/streaming/errors#status), then a fresh `snapshot`,
  then `delta`s resume. **Drop your book on `resyncing` and trust the next
  snapshot.**
* A mid-stream `snapshot` (seq jumps via a snapshot rather than a +1 delta) is
  normal and expected — replace your book and carry on.

Because of this contract, your apply loop needs no gap-handling logic of its
own. As a minimal-effort defensive check, track the last `seq` per
subscription; if a `delta` ever arrives where `seq !== last + 1`, you can simply
wait for the `snapshot` that the contract guarantees is coming.

The [trade channel](/streaming/trades) has its own per-market sequence space and
no resync mechanics — its `seq` works differently, so don't apply book
reasoning to it.
