# Venue depth

> Every price-level change at full depth, with nanosecond timestamps, and the top of book after each event.

Source: https://getmarkethistory.com/docs/depth

**Coming: being prepared.** No session is published yet, so these routes answer 404 for now; the
[changelog](https://getmarkethistory.com/docs/changelog) dates the first session when it is served. This page is the
reference for what they will return.

`stocks-venue-mbp` is one venue's book by price (market by price): **every price-level change at
full depth, with nanosecond timestamps**. Ask for `depth=1` and the same data comes back as the
top of book after each event that changed it. Coverage will run forward from the first session
published; each night will add the newest session, and published sessions are kept.

## Query

curl:

```bash
curl -sD - "https://getmarkethistory.com/query/v1/mbp/stocks-venue-mbp/AAPL?depth=1&start=2026-11-03T14%3A30%3A00Z&limit=10000" \
  -H "Authorization: Bearer $MARKET_HISTORY_KEY"
```

Python client:

```python
from markethistory import Client

mh = Client()  # reads MARKET_HISTORY_KEY

top = mh.mbp("AAPL", depth=1, start="2026-11-03T14:30:00Z", limit=10_000).to_pandas()
```

Plain `requests`:

```python
import json
import os

import requests

url = "https://getmarkethistory.com/query/v1/mbp/stocks-venue-mbp/AAPL"
params = {"depth": 1, "start": "2026-11-03T14:30:00Z", "limit": 10000}
headers = {"Authorization": f"Bearer {os.environ['MARKET_HISTORY_KEY']}"}

rows = []
while True:
    r = requests.get(url, params=params, headers=headers, timeout=60)
    r.raise_for_status()  # see /docs/errors for what each status means
    rows += [json.loads(line) for line in r.text.splitlines() if line]
    print(r.headers["X-Row-Count"], "rows,", r.headers["X-Bars-Charged"], "bars")
    if "X-Next-Cursor" not in r.headers:
        break
    params["cursor"] = r.headers["X-Next-Cursor"]
```

Response (shape and headers as served; values illustrative):

```http
HTTP/2 200
content-type: application/x-ndjson
x-row-count: 10000
x-bars-charged: 1000
x-next-cursor: eyJ…

{"ask_ct":2,"ask_px":348.52,"ask_sz":200,"bid_ct":1,"bid_px":348.49,"bid_sz":100,"sequence":4471022,"timestamp":"2026-11-03T14:30:00.000184211Z"}
```

One ticker per request. `/api/v1/sources` lists the dataset ids under `mbp`.

| Parameter      | Meaning                                                                               |
| -------------- | ------------------------------------------------------------------------------------- |
| `depth`        | Omit for every update. `1` for the top of book (below). Any other value is a 400.     |
| `start`, `end` | Event-time range (RFC 3339 or a bare date), both inclusive. Default: everything held. |
| `limit`        | Rows per page: default 10,000, maximum 100,000.                                       |
| `cursor`       | `X-Next-Cursor` from the previous page (it belongs to one ticker and one `depth`).    |
| `format`       | `jsonl` (default), `csv`, `json`, `parquet` or `arrow`. `mbt1` is bars only.          |

Pages run in the venue's sequence order. Follow `X-Next-Cursor` (or the `Link` header) until it is
absent: pages join exactly, with no row repeated or skipped, and the cursor holds no server state.
With `depth=1` a page can hold fewer rows than `limit`, even none, when the top stays unchanged
over a long stretch: the cursor still moves on, so keep following it.

## Columns: every update

| Column      | Type      | Meaning                                                                        |
| ----------- | --------- | ------------------------------------------------------------------------------ |
| `timestamp` | timestamp | matching-engine time, UTC, nanoseconds                                         |
| `sequence`  | integer   | the venue's message sequence number: unique, the order of record               |
| `side`      | string    | `B` bid, `A` ask                                                               |
| `price`     | float     | the level's price                                                              |
| `size`      | integer   | shares displayed at that level after the update; **0 means the level is gone** |
| `flags`     | integer   | bit 0 (1): the event is complete; bit 1 (2): the book is empty before this row |
| `orders`    | integer   | orders resting at the level after the update; null before 2024-12-09 (below)   |

Rows of one event share a `timestamp`; `sequence` orders them, and the event's last row has bit 0
of `flags` set. To rebuild the book at any instant, start from an empty book and apply rows in
`sequence` order: on bit 1 empty both sides, then set the level to `size` (remove it at 0). Bit 1
is set on each ticker's first row of a session.

## Columns: `depth=1`

| Column                       | Type      | Meaning                                   |
| ---------------------------- | --------- | ----------------------------------------- |
| `timestamp`, `sequence`      |           | the row of the event that changed the top |
| `bid_px`, `bid_sz`, `bid_ct` | float/int | best bid: price, shares, orders           |
| `ask_px`, `ask_sz`, `ask_ct` | float/int | best offer: price, shares, orders         |

A row is written at the end of each event whose top of book differs from the previous row's, so
the top in force at any instant is the last row at or before it. A side with no order is null in
its three columns; `*_ct` is also null where the order count is unknown. A crossed or locked book is
served as the venue published it.

`orders` and `*_ct` come from the venue's order-level feed, which exists from **2024-12-09**; before
that they are null. Where the order-level book disagrees with the level's displayed size, the count
is null rather than a guess.

## Price

The same bars as everything else: **10 rows are 1 bar**, at either depth. A page rounds up to a
block of 1,000 rows (100 bars), with a minimum of 1,000; an empty page is free. `X-Row-Count` is
rows, `X-Bars-Charged` is bars. The free plan's monthly bars pay for 1h bars only, so depth needs
bought bars.

## Free sample

No key: `/api/v1/mbp/stocks-venue-mbp/{ticker}` returns the first 1,000 rows after 09:30 ET of the
newest session held (`X-Preview-Limit: 1000`), at either depth, in any format but `mbt1`. It does
not page, and `start`, `end` and `cursor` are a 400 there.

```bash
curl "https://getmarkethistory.com/api/v1/mbp/stocks-venue-mbp/SPY?depth=1&format=csv"
```
