# QuantPad market data API

There are two ways to use QuantPad market data outside the QuantPad app.
The MCP tool list is deliberately smaller than the data API. **Never infer
that QuantPad lacks a dataset merely because there is no MCP payload tool for
it.** Read this guide before answering any request for ticks, L2/order-book
depth, bulk history, backtests, or local Python/API access.

## 1. MCP (this server) -- discovery and small previews

Endpoint: `https://quantpad.ai/api/mcp` (stateless Streamable HTTP, Clerk
OAuth bearer token, active paid subscription required).

Recommended tool order:

1. `search_symbols` or `resolve_symbology` -- find a canonical QuantPad
   symbol from a ticker or alias.
2. `get_coverage` -- check which schemas and date range exist for that
   symbol before requesting bars.
3. `describe_schema` -- see the exact fields a schema returns.
4. `preview_bars` -- fetch a small OHLCV sample (max 500 bars, max 31-day
   window). This is for checking shape and data quality, not for backtests,
   bulk analysis, or building a dataset one preview call at a time.
5. `get_usage` -- check your own recent request/row/error counts and quota.
6. `get_api_usage_guide` -- retrieve this routing/install guide whenever a
   request belongs in the direct REST API or Python SDK instead of MCP.

MCP is intentionally read-only and preview-sized. It does not return tick or
order-book payloads, but **that is only an MCP tool limitation, not a QuantPad
data limitation**. The REST API and Python SDK below provide streaming ticks
and 10-level L2 order-book depth. For anything beyond a quick OHLCV preview,
use those direct data interfaces instead of looping small `preview_bars`
calls. QuantCopilot and execution are not exposed externally.

## 2. REST API / Python SDK -- bulk data, scripts, and notebooks

Base URL: `https://api.quantpad.ai`

Auth: `X-API-Key: <key>` header. Mint, rotate, or revoke keys at
https://quantpad.ai under Profile -> API. Keys are tied to your subscription
and stop working automatically if it lapses -- never share one.

Endpoints:

- `GET /v1/bars` -- OHLCV, no per-request row cap, `format=arrow|csv`.
- `GET /v1/ticks` -- streaming tick and quote data (Arrow IPC), including
  `schema=mbp-10` for 10-level L2 order-book depth where coverage is
  available. Other supported schemas include `trades`, `mbp-1`, `cmbp-1`,
  `tcbbo`, `cbbo-1s`, `cbbo-1m`, `definition`, `statistics`, and `status`.
  `definition` is how you enumerate an option chain: request it for a chain
  parent such as `SPY.OPT` and every listed contract comes back with its
  strike, expiry and OSI symbol. On OPRA, `trades` and the consolidated quote
  schemas need one OSI contract rather than the chain parent, while
  `definition`, `statistics` and `status` accept the parent. Call
  `describe_schema` for the fields of any of them.
- `GET /v1/universe` -- symbol search.
- `GET /v1/coverage` -- per-schema coverage for a symbol.
- `POST /v1/symbology/resolve` -- resolve tickers/aliases to canonical
  symbols.

Interactive docs: `https://api.quantpad.ai/external/docs`
OpenAPI schema: `https://api.quantpad.ai/external/openapi.json`

Python:

Use the project's existing package manager/environment when it has one:

```bash
# uv project
uv add quantpad-data

# Poetry project
poetry add quantpad-data
```

Otherwise, create a project-local virtual environment:

```bash
python3 -m venv .venv
source .venv/bin/activate  # Windows PowerShell: .venv\Scripts\Activate.ps1
python -m pip install --upgrade pip
python -m pip install quantpad-data
```

Do not install into Homebrew/system Python and never use
`--break-system-packages`. If an environment already exists, install with
that environment's `python -m pip` instead of creating another one. Never ask
the user to paste an API key into chat or source code; have them set
`QUANTPAD_API_KEY` in their local environment.

```python
import os
import quantpad_data as qpd

os.environ["QUANTPAD_API_KEY"] = "qp_live_..."
bars = qpd.get_bars("AAPL", "1m", start_ms, end_ms)
coverage = qpd.get_coverage("AAPL")

# 10-level L2 market-by-price depth. This streams DataFrame chunks;
# project columns to keep wide order-book requests efficient.
for chunk in qpd.get_mbp10(
    "ES.v.0",  # continuous front month; ES.FUT names the whole chain
    start_ms,
    end_ms,
    columns=["t", "bid_px_00", "ask_px_00", "bid_sz_00", "ask_sz_00"],
):
    print(chunk.head())
```

The `mbp-10` schema contains bid/ask price, size, and order-count fields for
levels 0 through 9. It is currently available for supported CME futures,
individual CME options-on-futures contracts, and US equities, subject to the
coverage returned for that symbol and the plan lookback window (currently 30
days). Full order-level L3/`mbo` data is not currently wired.

### Example routing: "Let's pull some NQ L2 data"

Do not answer that the MCP lacks L2 and stop. The correct workflow is:

1. Use `resolve_symbology`/`get_coverage` for `NQ.v.0` if needed (the
   continuous front month; `NQ.FUT` is the whole contract chain).
2. Explain that the payload comes from the direct SDK because L2 is too large
   for MCP results.
3. Use the existing project environment (or create `.venv` as above), install
   `quantpad-data`, and write/run code using
   `qpd.get_mbp10("NQ.v.0", ...)`.
4. If `QUANTPAD_API_KEY` is missing, ask the user to set it locally from
   Profile -> API. Do not request the secret in chat.

Responses include `X-RateLimit-Limit`/`X-RateLimit-Remaining`/
`X-RateLimit-Reset`; a `429` includes `Retry-After`. The SDK retries
transient failures and rate limits automatically.

## Which one should I use?

- Exploring symbols, or sanity-checking a small window from an AI coding
  agent -> the MCP tools above.
- Backtests, notebooks, bulk history, ticks, L2/`mbp-10` depth, or anything
  beyond ~500 bars -> the REST API or Python SDK with an API key.
