> For the complete documentation index, see [llms.txt](https://docs.hello.trade/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.hello.trade/developer-tools/websocket-api/market-data/partial-order-book.md).

# Partial Order Book

Real-time order book snapshots with top levels of bids and asks.

**Channel:** `orderbook`

## Overview

The orderbook channel provides real-time snapshots of the order book showing configurable price levels on both bid and ask sides. Upon subscription, the current order book state is sent immediately. Afterward, updates are sent when the book changes.

## Connection

Connect to the WebSocket endpoint:

```
wss://marketdata.app.hello.trade/ws
```

## Subscription Request

```json
{
  "type": "subscribe",
  "channel": "orderbook",
  "symbols": ["BTC", "ETH"],
  "levels": 10,
  "orderbookInterval": 100
}
```

| Field               | Type      | Required | Description                                                                                                                                                                             |
| ------------------- | --------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `type`              | string    | Yes      | Must be `"subscribe"`                                                                                                                                                                   |
| `channel`           | string    | Yes      | Must be `"orderbook"`                                                                                                                                                                   |
| `symbols`           | string\[] | Yes      | List of instrument symbols                                                                                                                                                              |
| `levels`            | Number    | No       | Number of levels: `1`, `5`, `10`, `20`, or `100` (default: `10`). Max `20` with `orderbookInterval: 0`.                                                                                 |
| `orderbookInterval` | Number    | No       | Update interval in milliseconds: `100`, `1000`, or `2000` (default: `100`). `0` selects the [live stream](#live-stream-orderbookinterval-0).                                            |
| `decimals`          | Number    | No       | Group price levels to this many decimal places: bids round down, asks round up, equal buckets merge. Omit for raw price levels. `0` groups to whole prices. Max `8` on the live stream. |

## Live Stream (`orderbookInterval: 0`)

Setting `orderbookInterval` to `0` switches from sampled snapshots to an event-driven stream. Instead of polling the venue every N milliseconds, the server maintains the full book from the exchange's order-by-order feed and pushes a new top-`levels` snapshot every time the displayed book changes.

```json
{
  "type": "subscribe",
  "channel": "orderbook",
  "symbols": ["BTC"],
  "levels": 10,
  "orderbookInterval": 0
}
```

* The response shape is identical to the sampled stream (`bids`, `asks`, `timeStamp`), so existing parsers work unchanged.
* The current book is sent immediately on subscribe, then whenever the top `levels` of either side change. Changes deeper than your requested `levels` do not produce a message.
* Messages are coalesced with a 10 ms window per symbol (capped at 100 messages per second per symbol): several changes inside the window arrive as one message carrying the newest book, never a backlog. Every message is a complete snapshot.
* `levels` is capped at `20`. Deeper event-driven data is not offered on this channel because full snapshots scale with depth times change rate.
* `timeStamp` is the server-side time of the last applied change.
* If the server's upstream feed reconnects, there is a brief pause and then a fresh snapshot. Treat any gap longer than a few seconds as a signal to fall back to the sampled stream or the `ticker` channel.
* `decimals` works the same as on the sampled stream. `levels: 100`, `decimals` above `8`, and unknown symbols are rejected with a `400`. The `subscribed` confirmation lists only the symbols that were attached.
* For a few seconds after a server restart the live stream answers `503` with `"Live orderbook is loading, retry shortly"`. Retry with backoff, or use the sampled stream meanwhile.

## Unsubscription Request

```json
{
  "type": "unsubscribe",
  "channel": "orderbook",
  "symbols": ["BTC"]
}
```

## Response

```json
{
  "type": "marketData",
  "channel": "orderbook",
  "data": {
    "symbol": "BTC",
    "bids": [
      { "price": "45000.50", "quantity": "1.5", "numberOfOrders": "3" },
      { "price": "45000.00", "quantity": "2.3", "numberOfOrders": "5" },
      { "price": "44999.50", "quantity": "1.8", "numberOfOrders": "2" }
    ],
    "asks": [
      { "price": "45001.00", "quantity": "1.2", "numberOfOrders": "2" },
      { "price": "45001.50", "quantity": "2.1", "numberOfOrders": "4" },
      { "price": "45002.00", "quantity": "1.6", "numberOfOrders": "3" }
    ],
    "timeStamp": 1705596400000
  }
}
```

| Field       | Type   | Description                                                   |
| ----------- | ------ | ------------------------------------------------------------- |
| `symbol`    | string | Instrument symbol                                             |
| `bids`      | Array  | Bid price levels, sorted by price descending (best bid first) |
| `asks`      | Array  | Ask price levels, sorted by price ascending (best ask first)  |
| `timeStamp` | Number | Unix timestamp (milliseconds) of order book snapshot          |

**Price Level Structure:**

| Field            | Type   | Description                          |
| ---------------- | ------ | ------------------------------------ |
| `price`          | string | Price level                          |
| `quantity`       | string | Total quantity at this price level   |
| `numberOfOrders` | string | Number of orders at this price level |

## Error Response

```json
{
  "type": "error",
  "message": "Invalid subscription request",
  "code": 400
}
```

| Code | When                                                                                         |
| ---- | -------------------------------------------------------------------------------------------- |
| 400  | Invalid request, `levels: 100` or `decimals` above `8` on the live stream, or unknown symbol |
| 503  | Live stream not yet loaded after a server restart; retry                                     |

Unknown symbols are rejected with a `400` that names them. See [Unknown symbols](/developer-tools/websocket-api/market-data.md#unknown-symbols).

## Notes

* Configurable depth: 1, 5, 10, 20, or 100 levels per side
* Bids are sorted highest price first
* Asks are sorted lowest price first
* Empty arrays indicate no orders on that side
* Updates are sent only when the order book changes
* Update interval controls snapshot frequency (100ms, 1000ms, or 2000ms), or `0` for a push on every change
