API reference
Everything for the DepthFeed v3 API — authentication, every endpoint, the response contract, the data model, and the venues behind it. Base URL https://api.depthfeed.com/v3.
Contents▾
Introduction
DepthFeed is historical order-book depth for prediction markets — recorded full bid/ask ladders on both sides for Polymarket, Kalshi, and Limitless. Not just the last trade price or top of book: each stored observation includes resting levels and sizes. It is the data you need to backtest a fill against the liquidity that was actually there.
It is delivered over a metered REST API — market discovery, metadata, and latest + historical order-book snapshots, keyset-paginated with separate general-admission and historical-workload controls. Pull exactly the depth your strategy needs and replay it in your own stack.
Order-book coverage spans 3 venues, 7 assets (btc · eth · sol · xrp · doge · bnb · hype) and the recurring up/down crypto markets each venue runs (5m, 15m, 1h, 4h, 24h, depending on venue).
Prices are the second half of the product. /v3/bars serves OHLCV price bars for US-listed equities and ETFs, crypto spot pairs and perpetual futureson every plan, at one-minute base resolution. They share the clock, the schema and the plan history window with the books above, so a strategy can read an equity and act on a contract without reconciling two vendors’ timestamps.
The Desk plan also bundles realtime sports— live Polymarket & Kalshi books, sportsbook odds, scores and injuries across the major leagues. Jump to the Sports endpoints.
New to evaluating data sources? The buyer’s guide covers the five criteria that decide whether prediction-market data is actually backtestable, and how DepthFeed clears each.
Quickstart
1. Create a free account and mint an API key from the dashboard. Keys look like df_… and are shown once.
2. Make your first authenticated call:
curl https://api.depthfeed.com/v3/whoami \
-H "Authorization: Bearer df_your_key_here"3. The response is a JSON envelope — your plan, limits, and history window:
{
"data": {
"user_id": "acct_…", "plan": "pro",
"rps": 25, "rpm": 1000, "history_days": 30, "coins": "all", "sports": false,
"bars": { "max_symbols_per_request": 8 }
},
"meta": { "request_id": "req_…", "timestamp": "2026-06-07T02:27:09.532Z" }
}4. Pull the latest BTC up/down markets, then the order-book depth for one of them — see Markets and Snapshots.
Authentication
Every endpoint except /v3/health and /v3/overview requires an API key. Pass it either way — both schemes are accepted:
# Authorization header (recommended)
curl https://api.depthfeed.com/v3/btc/markets -H "Authorization: Bearer df_your_key"
# or the X-API-Key header
curl https://api.depthfeed.com/v3/btc/markets -H "X-API-Key: df_your_key"/v3/streamalso requires a key, but authenticates once at connection time — a WebSocket can’t carry a per-request header, so it accepts X-API-Key, Authorization: Bearer, or a ?api_key= query param. See Live stream.Keys are minted per account from the dashboard and carry a plan that sets your rate limit, history window, and asset/venue access. Keys are stored SHA-256-hashed at rest — the raw value is shown exactly once at creation. Revoking a key in the dashboard takes effect immediately. Quotas are per user, not per key — extra keys do not multiply your limit.
| Failure | Status | code |
|---|---|---|
| No key supplied | 401 | AUTH_MISSING |
| Unknown / revoked / malformed key | 401 | AUTH_INVALID |
| Key store temporarily unreachable | 503 | AUTH_UNAVAILABLE |
Base URL & versioning
All endpoints live under a single versioned base path:
https://api.depthfeed.com/v3TLS is required (Let's Encrypt, HTTP/2). The current API version is v3, built to PolyBackTest parity (same envelope, cursor pagination, and error-code enum) over our superset data (3 venues, 7 assets). Legacy v1/v2 namespaces are not served.
Response format
Every successful response is the same envelope:
{
"data": … , // object (single) or array (list)
"pagination": { … }, // present only on list endpoints
"meta": { "request_id": "req_…", "timestamp": "2026-06-07T02:27:09.532Z" }
}Errors share the shape, with the HTTP status set per code:
{
"error": { "code": "INVALID_COIN", "message": "…", "details": { … } },
"meta": { "request_id": "req_…", "timestamp": "…" }
}Every response — success or error — carries meta.request_id, also returned as the X-Request-Id header. Quote it in support requests.
Errors
Branch on error.code — it is stable. The HTTP status is implied by the code.
| code | HTTP | Meaning |
|---|---|---|
AUTH_MISSING | 401 | No API key on the request. |
AUTH_INVALID | 401 | Key is unknown, revoked, or malformed. |
COIN_NOT_IN_PLAN | 402 | Your plan does not include that coin (e.g. eth on Free). |
ENDPOINT_NOT_IN_PLAN | 402 | Limitless, Predict.fun and live Kalshi depth require a paid plan. Kalshi HISTORY does not — it is bounded by your plan window like Polymarket's. |
SYMBOL_LIMIT_EXCEEDED | 402 | More symbols in one /v3/bars request than your plan's batch size (3 / 8 / 16 / 32). Split the list and re-request — this bounds ONE call, not how many symbols you may pull. |
WINDOW_TOO_WIDE | 400 | One /v3/bars request spans more time than the frame's row count allows (45 days at 1Min, 180 at 5Min, a year at 15Min and 1Hour, ten years at 1Day). Page with limit and cursor. |
HISTORY_LIMIT_EXCEEDED | 403 | start_time / timestamp is older than your plan window. |
INVALID_COIN | 400 | Coin not one of the seven supported. |
INVALID_CURSOR | 400 | Cursor is malformed. |
INVALID_TIMESTAMP | 400 | Not ms-epoch or ISO-8601. |
INVALID_INTERVAL | 400 | interval not a duration like 30s, 1m, 5m, 1h, 1d (1s–1d). |
INVALID_SLUG | 400 | Empty/invalid {slug} path segment (e.g. a missing URL variable). |
INVALID_TICKER | 400 | Empty/invalid {ticker} path segment. |
MARKET_TICKER_REQUIRED | 400 | A Kalshi series was passed where an exact discovered market ticker is required. |
BATCH_TOO_LARGE | 400 | More than 10 sub-requests in a batch. |
BATCH_INVALID_PATH | 400 | Sub-request is not a GET /v3/ path (per-sub status). |
MARKET_NOT_FOUND | 404 | No market with that id / slug / ticker. |
SNAPSHOT_NOT_FOUND | 404 | No book has been captured for the query — the market may not have opened for trading yet, may have expired, or may be outside coverage. |
ENDPOINT_NOT_FOUND | 404 | Path matches no v3 route. |
RATE_LIMIT_BURST | 429 | Per-second burst exceeded. |
RATE_LIMIT_SUSTAINED | 429 | Per-minute sustained limit exceeded. |
HISTORY_CONCURRENCY_LIMIT | 429 | Another snapshot or batch history request is still running for this account (details.scope = "account"). |
HISTORY_POOL_BUSY | 429 | The shared archive-query pool is saturated server-side, not your account's limit (details.scope = "shared_pool") — retry with backoff. |
INTERNAL_ERROR | 500 | Unexpected server error — retry, then contact us with the request id. |
AUTH_UNAVAILABLE | 503 | Key verification is temporarily unavailable — retry shortly. |
UPSTREAM_UNAVAILABLE | 503 | A depth service behind the API did not answer (details.retryable = true). This is about us, not your ticker — retry with backoff rather than treating the market as missing. |
BARS_BUSY | 503 | The bar service is at its concurrency ceiling right now, not an outage. Carries details.retry_after in seconds — back off and retry, the same request usually succeeds. |
403 HISTORY_LIMIT_EXCEEDED carries details.max_history_days and details.oldest_allowed. 429 also sets Retry-After and the X-RateLimit-* headers.
Rate limits
Limits are a per-user token bucket with two windows: a per-second burst and a per-minute sustained cap. Exceeding either returns 429 with the matching code and a Retry-After of 1 second.
The advertised rps/rpm values are general REST admission limits, not archive-delivery rates. Historical snapshots, batches containing history reads, and other heavyweight routes use separate account-level concurrency and delivery controls. These controls apply independently of the general token bucket and do not change the plan's history window.
Explorer, Quant, and Research currently accept one historical request in flight per account. Desk accepts 2 parallel historical snapshot requests per account through its dedicated Desk query pool. An overlap returns 429 HISTORY_CONCURRENCY_LIMIT with Retry-After: 2; retry only after an active request completes. General rps/rpm values must not be used to infer historical parallelism.
A historical read can also be rejected when your account is still inside its own allowance, because the shared archive-query pool is saturated. That case returns 429 HISTORY_POOL_BUSY with details.scope = "shared_pool" instead of "account". Branch on details.scope: on account, lower your parallelism; on shared_pool, lowering parallelism will not help — retry with backoff.
/v3/bars has its own concurrency ceiling, independent of both controls above. Past it a request is refused immediately with 503 BARS_BUSY and details.retry_after in seconds, rather than being queued — a fast refusal you can retry is more useful than a slow success you cannot budget for. Treat it exactly like a 429: back off and retry the same request. Bars also carry two limits that are not rate limits at all — batch size (402 SYMBOL_LIMIT_EXCEEDED) and per-request span (400 WINDOW_TOO_WIDE) — both fixed by splitting the request, not by waiting.
| Header | Meaning |
|---|---|
X-RateLimit-Limit | Your per-second burst limit (rps). |
X-RateLimit-Remaining | Burst tokens left this second. |
Retry-After | Seconds to wait (set on 429). |
X-Request-Id | Echo of meta.request_id. |
See Plans & access for the rps/rpm per tier.
Historical query pattern
Keep no more than your confirmed history concurrency active. Use bounded start_time andend_time, cursor pagination, and limit=1000; omit include_count and request the full ladder only when needed. Add interval when a downsampled series is sufficient. DepthFeed is a metered query-access product: bulk files, offline archive delivery, database replication, and systematic archive mirroring are not included.
Pagination & filters
List endpoints use opaque keyset cursors — O(1) at any depth. Pass ?cursor= from the previous page's pagination.next_cursor; stop when has_more is false.
"pagination": {
"next_cursor": "6274…", // opaque; feed back as ?cursor=
"has_more": true,
"limit": 50,
"count": 50,
"total_count": 1284 // only when ?include_count=true
}Common query parameters
| Param | Type | Notes |
|---|---|---|
limit | int | Markets max 100, snapshots/trades max 1000. Defaults: 50 / 100. |
cursor | string | Opaque keyset cursor from the prior page. |
include_count | bool | Adds total_count (costs a COUNT — opt-in). |
start_time | ts | ms-epoch or ISO-8601. Older than your window → 403. |
end_time | ts | ms-epoch or ISO-8601. |
interval | dur | Snapshots only. Downsample to one book per bucket (latest in each): 30s, 1m, 5m, 1h … up to 1d. Omit for full resolution. |
Timestamps accept either milliseconds-since-epoch (e.g. 1780774485780) or ISO-8601 (e.g. 2026-06-07T02:27:09Z). Every value reaching the database is validated and injection-safe. The plan history window is enforced on every list/snapshot endpoint: an explicit start_time beyond the window returns 403; an omitted one is clamped to the window floor.
Downsampling with interval
By default the snapshot endpoints return every recorded book change — full event-driven resolution. When you only need a periodic sample (say one book per minute for a chart or a coarse backtest), add ?interval= and the server collapses each time bucket to a single snapshot: the most recent book in that bucket. It is far less data over the wire than fetching every tick and thinning client-side.
# one snapshot per minute instead of the raw stored series
curl "https://api.depthfeed.com/v3/btc/markets/{id}/snapshots?interval=1m&include_orderbook=true" \
-H "Authorization: Bearer df_your_key"Accepts a duration: a bare number of seconds, or a value with a unit — 30s, 1m, 5m, 15m, 1h, 4h, 1d — from 1s to 1d. Buckets are aligned to the epoch, so 1m snaps to wall-clock minute boundaries. Cursor pagination and include_count apply to the downsampled rows (total_count becomes the number of buckets). Omit it, pass raw, or pass 0 for full resolution. An unrecognised value returns 400 INVALID_INTERVAL. Works on every snapshot endpoint — Polymarket, Kalshi, Limitless, and Binance.
Plans & access
Four flat plans. The plan field returned by /v3/whoami is the raw value in the right column.
| Plan | plan | Price | General rps | General rpm | Historical parallelism | Unified history | Wallet Intelligence | Crypto | Sports REST | Live sports books |
|---|---|---|---|---|---|---|---|---|---|---|
| Explorer | free | $0 | 1 | — | 1 | 7 days | 1 saved · 3 audits | BTC sample | All sports venues | REST only |
| Quant ★ | pro | $29/mo | 25 | 1,000 | 1 | 30 days | 5 saved · 10 audits | All assets + venues | All sports venues | 1 |
| Research | scale | $99/mo | 50 | 3,000 | 1 | 90 days | 10 saved · 25 audits | All assets + venues | All sports venues | 2 |
| Desk | enterprise | $249/mo | 100 | 6,000 | 2 parallel | Full archive | 20 saved · 50 audits | All; dedicated Desk historical query pool | All sports venues | 3 |
There are no Polymarket or Kalshi add-ons. Both sports venues use the same key, schema, rate limit, and history window; upgrading buys more history, throughput, and live-book concurrency.
The General rps/rpm columns describe request admission, not simultaneous archive scans. Historical query parallelism and delivery controls are separate. Desk historical reads use a dedicated Desk-only query pool isolated from regular-plan query traffic, without removing account-level controls. The pool is shared across Desk accounts and is not customer-owned or account-exclusive infrastructure.
Gating is enforced server-side:
- Coins — a non-BTC coin on Free →
402 COIN_NOT_IN_PLAN. - Venues — Kalshi and Limitless on Free →
402 ENDPOINT_NOT_IN_PLAN. - Sports — the /v3/sports/* REST surface is included on every plan; the same plan history window applies to both venues.
- History —
start_timebeyond your window →403 HISTORY_LIMIT_EXCEEDED. - Price bars — /v3/bars obeys the same history window as depth, and additionally caps symbols per request (3 / 8 / 16 / 32), over which it returns
402 SYMBOL_LIMIT_EXCEEDED. - Streaming — limits apply at subscribe time on /v3/stream; Quant and up stream every venue, Explorer streams Polymarket + Binance (BTC) — Kalshi and Limitless channels require a paid plan. Streaming is live depth; Kalshi HISTORY is on every plan, bounded by your window.
Health & identity
/v3/healthno authLiveness probe, no auth. Returns { status: "ok", service, time }.
/v3/whoamiYour plan, rate limits, unified history window, coin access, and sports access — the fastest way to confirm a key works.
Markets
Polymarket up/down markets per coin, joined to settlement reference (open/close price, winner, volume). {coin} is one of btc · eth · sol · xrp · doge · bnb · hype.
/v3/{coin}/marketsFilters: type (5m/15m/1h/4h/24h), resolved (true/false), plus the common time + pagination params.
/v3/{coin}/markets/{market_id}/v3/{coin}/markets/by-slug/{slug}A single market by id or slug. Example response (per-coin price keys are dynamic, like the reference):
{ "data": {
"market_id": "2456720", "event_id": "566750",
"slug": "btc-updown-5m-1780860300", "market_type": "5m",
"start_time": "…", "end_time": "2026-06-07T19:30:00Z",
"condition_id": "0xb7ce…",
"clob_token_up": "15598…", "clob_token_down": "51823…",
"btc_price_start": null, "btc_price_end": null,
"winner": null, "final_volume": null, "final_liquidity": null, "resolved_at": null
}, "meta": { … } }*_price_*, winner, resolved_at, final_volume, and final_liquidity — are null until the market settles and the reference backfills (~12–24 h after settlement)./v3/polymarket/marketspaid planThe whole Polymarket venue, not just the crypto up/down markets. The routes above address markets by coin, so they can only reach markets that have one — elections, geopolitics, equities and FX have no coin and no URL there. This lists everything.
Filters: ?q= (slug search), ?type=eventfor everything that isn't an up/down ladder, plus ?coin=, ?event= and ?outcome=. Markets here are keyed by CLOB asset_id (token id); pass that to /v3/polymarket/{asset_id}/snapshots for depth history or /v3/polymarket/{asset_id}/ticks for the tape. Non-crypto markets carry an empty base_asset— they have no coin, and we don't invent one.
Order-book snapshots
The order-book depth time-series for a market, with the underlying coin price stamped on each snapshot.
/v3/{coin}/markets/{market_id}/snapshotsAdd ?include_orderbook=true to get the full ladder (omitted by default for a lighter payload). Time-windowed + cursor-paginated. Add ?interval=1m (or 5m, 1h, …) to downsample to one book per bucket instead of the raw stored series — see Pagination & filters. The list response is an array with a pagination block:
{ "data": [{
"id": "1780774485780", "time": "2026-06-06 19:34:45.780",
"market_id": "2456720", "btc_price": 60606.68,
"price_up": 0.505, "price_down": 0.495,
"orderbook_up": { "bids": [[0.50, 304.25], …], "asks": [[0.51, 30.0], …] },
"orderbook_down": { "bids": [ … ], "asks": [[0.50, 304.25], …] }
}], "pagination": { … }, "meta": { … } }/v3/{coin}/markets/{market_id}/snapshots/at/{timestamp}The single snapshot closest to a timestamp (within ±2 s). {timestamp} is ms-epoch or ISO-8601. Unlike the list endpoint, data is a single object (the same row shape) with no pagination block; no match within ±2 s returns 404 SNAPSHOT_NOT_FOUND.
{ "data": {
"id": "1780774485780", "time": "2026-06-06 19:34:45.780",
"market_id": "2456720", "btc_price": 60606.68,
"price_up": 0.505, "price_down": 0.495,
"orderbook_up": { "bids": [[0.50, 304.25], …], "asks": [[0.51, 30.0], …] },
"orderbook_down": { "bids": [ … ], "asks": [[0.50, 304.25], …] }
}, "meta": { … } }Levels are [price, size]. price_up is the best-bid/ask midpoint; price_down = 1 − price_up. The orderbook_down side is derived as the binary complement of the up book (down = 1 − up, sizes preserved). The coin price is the nearest preceding tick via an ASOF join — exact for 1h/4h/24h, a labeled Binance proxy for 5m/15m.
Tick data — every book change
The raw tape: every individual order-book change, not a sampled snapshot series. Where snapshots give you the book at points in time, ticks give you every change between them — what a market-making or execution-research workflow needs to ask where the book was the instant before a fill, or how long a level rested before it was taken.
Enterprise only. Other plans receive 402 TICKS_NOT_IN_PLAN.
/v3/{coin}/markets/{market_id}/ticksenterprisePolymarket, sourced from the CLOB delta stream. Both outcome tokens are returned by default and tagged outcome; narrow with ?outcome=up or ?outcome=down.
History: approximately 45 days of continuous tick history. Older isolated days exist in the archive but are not contiguous, so treat 45 days as the dependable window.
Coverage: the up/down markets on the 5m, 15m and 24h windows, across all seven assets. The 1h and 4h up/down families are not currently in the tick tape — use snapshots for those.
{ "data": [{
"id": "1780774485780", "time": "2026-06-06 19:34:45.780",
"received_ms": "1780774485812", "outcome": "up",
"token_id": "7194…", "side": "BUY", "price": 0.505, "size": 1240.0
}], "pagination": { … }, "meta": { … } }/v3/kalshi/{ticker}/ticksenterpriseNew — Kalshi tick capture began 2026-08-07. There is no Kalshi tick history before that date; the tape accumulates forward from it. Kalshi snapshots remain available over the full history window.
Coverage is a rolling subset, not every Kalshi market: the seven crypto assets, prioritised by nearest expiry, with a bounded number of markets taped concurrently. Contact us if you need a specific series covered.
Sourced from the authenticated orderbook_delta WebSocket. kind is snapshot for the rows that anchor a book (so any window you request starts from complete state) or delta for a change. delta is the signed size change and size is the resting size at that price after it. seqis Kalshi's own sequence number for the capture session — it increments by exactly one across the session, so you can verify a stretch of tape is complete rather than take our word for it. A run of snapshot rows marks a new session, where it restarts. Narrow to one side with ?side=yes or ?side=no.
{ "data": [{
"id": "1780774485780", "time": "2026-06-06 19:34:45.780",
"received_ms": "1780774485791", "seq": "418823",
"kind": "delta", "side": "yes", "price": 0.62, "delta": -85.0, "size": 240.0
}], "pagination": { … }, "meta": { … } }Pages hold up to 10000 rows (default 1000) and are cursor-paginated like every other list endpoint. Many ticks routinely share one millisecond, so cursors carry a position within a timestamp — paginating a busy market never splits or drops the rows sharing a boundary instant.start_time/end_timeand your plan's history window apply as usual.
Binance — spot & futures
The underlying-asset book and trade tape from Binance. {venue} is spot or futures. The book is 20 levels per side.
/v3/{coin}/{venue}/latest/v3/{coin}/{venue}/snapshotsLatest book / paginated book history. Each snapshot: price (mid), bids, asks, timestamp.
/v3/{coin}/{venue}/trades/v3/{coin}/{venue}/trades/latest1-second OHLCV candles with an aggressive buy/sell split — exact, 1:1 with the reference:
{ "data": [{
"id": "1780747762000", "timestamp": "2026-06-06 12:09:22.000",
"price_open": 61097.1, "price_high": 61097.1,
"price_low": 61097.09, "price_close": 61097.1,
"total_volume": 0.01667,
"aggressive_buy_volume": 0.0156, "aggressive_sell_volume": 0.00107,
"num_trades": 3
}], "pagination": { … }, "meta": { … } }Price bars — equities & crypto
OHLCV price bars for US-listed equities and ETFs, Binance spot pairs, and perpetual futures. One minute is the finest resolution; the coarser frames are rolled up from it.
/v3/barssymbols is a comma-separated list. timeframe is one of 1Min, 5Min, 15Min, 1Hour or 1Day (default 1Min). start_time, end_time, limit and cursor behave exactly as they do on every other collection here.
venue is optional and selects the market outright: us-equities, binance (spot) or binance-futures (perpetuals). Leave it off and a bare symbol is resolved for you — equities first, then Binance spot. Name it and you get that market or nothing, which is what you want when a string could be two instruments.
limit is bars per symbol. A request without one is not paged at all, because the natural bars pull is a whole window and a default page size would quietly hand back a short series — which is indistinguishable from a gap in the data. When you do page, every series is cut at the same instant and pagination.next_cursor resumes exactly there: no overlap, no gap.
curl -H "X-API-Key: $DEPTHFEED_KEY" \
"https://api.depthfeed.com/v3/bars?symbols=AAPL,BTCUSDT&timeframe=1Hour&start_time=2026-08-01T00:00:00Z"{ "data": {
"timeframe": "1Hour",
"license_class": "source_attributed_public_serving",
"attribution": "Market data via QuarterTrace. Source-attributed; not a consolidated (SIP) feed.",
"series": [{
"symbol": "AAPL", "timeframe": "1Hour", "assetClass": "equity",
"source": "yahoo_finance", "derived": true,
"t": [1785974400000, 1785978000000],
"open": [306.83, 307.04], "high": [307.9, 308.1],
"low": [306.1, 306.55], "close": [307.04, 307.8],
"volume": [1043200, 887400]
}]
}, "meta": { … } }How to spell a symbol
Equities and ETFs are their ordinary ticker: AAPL, SPY, BRK-B. A crypto pair is spelled the way the venue spells it, so it is BTCUSDT rather than BTC. A perpetual future takes a .P suffix — BTCUSDT.P, AAPLUSDT.P — because the spot pair and the perp are different instruments trading at different prices, and a flat symbol space that quietly picked one for you would be picking which market your strategy measured.
BTCU, ETHU and WLDU. Each resolves to the equity, decided against the symbol universe rather than your date range — so the answer never changes when you move the window. The crypto pair is still reachable under its own venue spelling.Derived frames
Equities are collected at 1Min and 1Day; crypto is collected at 1Min. Anything else is aggregated on read, and a series says which it is with derived. An aggregated bar takes the first bar's open and the last bar's close, the extremes of the high and low, and the sum of the volume, over UTC-aligned buckets.
Limits
Three separate bounds, and they fail with three different codes. Your plan's history window applies here as it does everywhere else — past it, 403 HISTORY_LIMIT_EXCEEDED. Symbols per request is 3 on Explorer, 8 on Quant, 16 on Research, 32 on Desk; over that, 402 SYMBOL_LIMIT_EXCEEDED. And a single request may only span as much time as the frame's row count allows — 45 days at 1Min, 180 at 5Min, a year at 15Min and 1Hour, ten years at 1Day — over which it returns 400 WINDOW_TOO_WIDE. Page with limit and cursor to walk a range wider than one request carries.
A fourth response is not a limit but a moment: 503 BARS_BUSY means the bar service is at its concurrency ceiling right now. It carries details.retry_after in seconds, like a rate-limit refusal, and the same request usually succeeds on the next attempt — treat it as back off and retry, not as an outage.
403 HISTORY_LIMIT_EXCEEDED, with oldest_allowed in the details). The open-source Strategy Builder reads this exact endpoint with your own key, so a backtest there reaches back exactly as far as your plan does here.attribution string and each series names its own source; both have to travel with the data if you display it.Kalshi
Kalshi's crypto contracts — full yes/no depth the reference doesn't carry. Paid plans only. 21 series for all 7 assets: 15-minute KX{ASSET}15M, threshold KX{ASSET}, and directional KX{ASSET}D. The threshold and directional series each run hourly, daily, and weekly markets concurrently — market_typecarries each market's actual window.
/v3/kalshi/marketsFilters: ?coin= (base asset), ?type= (window), and exact ?series= (for example KXBTC15M). For historical downloads, pass start_time and end_time here first and use the returned venue-native tickers. Do not generate Kalshi ticker ids from UTC timestamps; the venue's ticker clock convention changed historically.
/v3/kalshi/{ticker}/orderbook/latestpaid planNewest full yes/no book for a ticker. yes/no are [price, size] arrays (prices in 0–1 dollars).
{ "data": {
"ticker": "KXHYPED-26JUN0717-T73.9999", "series": "KXHYPED",
"base_asset": "hype", "market_type": "24h",
"id": "1780…", "timestamp": "…",
"yes": [[0.62, 1400], …], "no": [[0.38, 900], …]
}, "meta": { … } }/v3/kalshi/{ticker}/snapshotsThe historical yes/no depth series for one exact discovered market ticker — same row shape, ordered by receive time, time-windowed + cursor-paginated (include_count opt-in, max 1000). The forward-captured Kalshi book history from a paced REST polling loop. Effective cadence varies with the active market set and API limits; it uses the same historical endpoint pattern as Polymarket and Limitless /snapshots, so Kalshi depth is backtestable too. Passing a series such as KXBTC15M, or an invented historical ticker, returns an explicit discovery error instead of a misleading empty page.
/v3/kalshi/{ticker}/candlesHourly OHLC of the yes bid, the yes ask and the traded price, plus volume and open_interest. This is the only history that exists for most of the Kalshi catalog: Kalshi serves no historical order book, so a market that closed before our book capture began has no /snapshots and no /ticks — but it does have candles, reaching back up to a year.
Time-windowed and cursor-paginated like /snapshots(max 5000 rows), clamped to your plan's history window. ?interval= selects the candle period; only 1h is recorded, and any other value returns an explicit error naming what exists rather than an empty page. Candles are stored as recorded and never resampled, so a shorter period is never synthesised from a longer one.
price is null when nothing traded in the period — about 95% of them. The quote sides are always real, so a quiet hour still tells you where the book stood. Coverage is long-lived markets (open to close longer than 24 hours); short-dated crypto ladders are captured at full resolution by /snapshots and /ticks instead, and asking for their candles returns a 404 that says so.
{ "data": [{
"ticker": "KXFEDDECISION-26JUL-H26", "series": "KXFEDDECISION",
"market_type": "1w", "id": "1786168800000", "timestamp": "…",
"period_minutes": 60,
"yes_bid": { "open": 0.56, "high": 0.58, "low": 0.55, "close": 0.57 },
"yes_ask": { "open": 0.64, "high": 0.65, "low": 0.62, "close": 0.63 },
"price": { "open": 0.60, "high": 0.61, "low": 0.59, "close": 0.61 },
"volume": 240, "open_interest": 1180
}], "pagination": { … }, "meta": { … } }Comparing all three venues at once? Start from the cross-venue screener instead of stitching per-venue calls.
Limitless
Limitless Exchange — a CLOB on Base running recurring up/down crypto markets at 5m and 15m. Depth is captured live over its order-book websocket (so even the fast 5m books are recorded). Paid plans only. {slug} looks like btc-up-or-down-15-min-1780798512077.
/v3/limitless/marketspaid planCurrently-open slots. Filters: ?coin= and ?type= (5m/15m).
/v3/limitless/{slug}/orderbook/latestpaid planNewest L2 depth for a slug (bids descending, asks ascending):
{ "data": {
"slug": "btc-up-or-down-15-min-1780798512077", "condition_id": "0x…",
"base_asset": "btc", "market_type": "15m",
"id": "1780798…", "timestamp": "2026-06-07 02:27:09.532", "midpoint": 0.5,
"bids": [[0.45, 200.0], …], "asks": [[0.46, 120.0], …]
}, "meta": { … } }/v3/limitless/{slug}/snapshotspaid planThe historical depth series for one slug — same row shape, ordered by receive time, time-windowed + cursor-paginated. This is the forward-captured order-book history.
Binance prediction markets
Binance Wallet's Predict.fun-backed crypto prediction markets, normalized into a dedicated DepthFeed namespace. The initial catalogue covers BTC, ETH, and BNB up/down markets. Paid plans only.
/v3/binance-prediction/marketspaid planFilter with ?coin=btc, ?type=5m, or ?status=resolved. Results include the market/topic IDs, condition and token metadata, resolution, winning outcome, volume, liquidity, participant count, chain, and exchange contract.
/v3/binance-prediction/{market_id}/orderbook/latestpaid plan/v3/binance-prediction/{market_id}/snapshotspaid planLatest and historical full L2 depth. The standardized BTC 15-minute lifecycle panel begins 26 June 2026; stable one-minute forward capture across tracked live markets begins 26 July. Earlier resting books cannot be reconstructed from settlement data.
/v3/binance-prediction/{market_id}/timeseries?metric=chancepaid plan/v3/binance-prediction/{market_id}/timeseries?metric=pricepaid plan/v3/binance-prediction/{market_id}/timeseries?metric=last_tradepaid plan/v3/binance-prediction/{market_id}/tradespaid planProbability, displayed price, and last-trade samples are kept separately and begin on 17 July 2026. The trades route is reserved while historical fills are reconstructed from BNB Smart Chain logs and currently returns an empty historical dataset.
/v3/predictfun/* paths remain compatible aliases. Customers use a DepthFeed key; no Binance key or wallet pairing is required.Cross-venue screener
Start here for anything cross-venue. The screener answers the core question — how is the same “up or down” market priced on Polymarket, Kalshi, and Limitless right now? — in a single request, so you never stitch the three per-venue endpoints (with their three different identifiers) together yourself. Plan-aware: on Free you see BTC + Polymarket; the Limitless cells fill in on a paid plan; the Kalshi cell is live depth, so it does too. Kalshi history is on every plan.
/v3/screenerThe grid: one cell per asset with each venue's latest “up” probability, best bid/ask, and settlement reference. A placeholder/empty book reports null rather than a meaningless 0.50.
{ "data": {
"assets": ["btc","eth","sol","xrp","doge","bnb","hype"],
"windows": ["5m","15m","1h","4h","24h"],
"cells": [{ "asset": "btc",
"polymarket": { "up": 0.735, "down": 0.265, "best_bid": 0.73, "best_ask": 0.74, "price_to_beat": 62764.0 },
"kalshi": { "up": 0.71, "down": 0.29, … },
"limitless": { "up": 0.75, "down": 0.25, "slug": "btc-up-or-down-…", … } }],
"paid": true
}, "meta": { … } }/v3/screener/{asset}/{window}Drill into one (asset, window): the full L2 book on every venue side by side (books.polymarket / books.kalshi / books.limitless), plus the underlying spot series and the settlement price_to_beat — the single call a cross-venue backtest or arb screen actually needs.
/v3/overviewno authPer-asset, cross-venue time-series overview (price segments per window) — what powers the dashboard overview chart. Public, no key required; select with ?asset=.
Batch
/v3/batchRun up to 10 GET /v3/ requests in one round-trip. Each sub-request is dispatched independently and gets its own status.
curl -X POST https://api.depthfeed.com/v3/batch \
-H "Authorization: Bearer df_your_key" -H "Content-Type: application/json" \
-d '{ "requests": [
{ "id": "a", "method": "GET", "path": "/v3/btc/markets?limit=1" },
{ "id": "b", "method": "GET", "path": "/v3/limitless/markets?type=5m&limit=1" },
{ "id": "c", "method": "GET", "path": "/v3/bars?symbols=BTCUSDT&timeframe=1Hour" }
] }'A contract's depth and the underlying's price bars in one round-trip is the pairing this exists for — /v3/bars is a sub-request like any other.
Returns { data: [ { id, status, body }, … ] } with an outer 200. Over 10 sub-requests → 400 BATCH_TOO_LARGE; a non-GET or non-/v3/ path gets a per-sub 400 BATCH_INVALID_PATH.
Sports
Realtime sports prediction-market data — live order-book depth on Polymarket and Kalshi, alongside sportsbook odds, live scores, and an injury feed across the major leagues (NBA, NFL, MLB, NHL, soccer, tennis, UFC, F1 and more). Both venues are included together on every tier; plans change the shared history window, throughput, and live-book concurrency. Same{ data, meta, pagination } envelope, auth, and cursor pagination as the rest of the API.
Discovering a market. Walk the funnel: /v3/sports/leagues → /v3/sports/markets?league=… → take a market's tokens[](each is one outcome's asset_id) → /v3/sports/books/{asset_id}/latest for the live book. Or start from /v3/sports/overview, which answers “what's trading now, on every venue” in one call.
/v3/sports/overviewStart here. The live cross-sport board — every tracked league with its in-progress and upcoming games, current prices, and best bid/ask per venue, in a single request.
/v3/sports/leaguesThe leagues we track, each with its game and market counts — the top of the discovery funnel.
/v3/sports/marketsSports markets across Polymarket and Kalshi. Filter with ?league= (e.g. nba, mlb, soccer); cursor-paginated like every list endpoint (?limit=, ?cursor=). Each market carries its condition_id, market_slug, outcomes, and tokens — the per-outcome asset_ids you hand to the book endpoint.
{ "data": [{
"condition_id": "0xfb53…", "market_slug": "mls-nyc-laf-…-total-2pt5",
"league": "soccer", "kind": "totals", "title": "New York City FC vs. Los Angeles FC",
"outcomes": ["Over", "Under"],
"tokens": ["45485059…", "38846626…"], // one asset_id per outcome
"game_start": "2026-11-05T00:30:00Z", "resolved": false
}], "pagination": { "next_cursor": "…", "has_more": true, "limit": 50 }, "meta": { … } }/v3/sports/books/{asset_id}/latestNewest recorded full order book for one outcome — the asset_idis a token from the market'stokens[]. Same [price, size] bid/ask ladder shape as the crypto book endpoints. For latency-sensitive live use, Quant and higher tiers can subscribe to the sports WebSocket channels below.
/v3/sports/books/{asset_id}/historyHistorical full-ladder snapshots for the outcome. Page with ?limit= and ?cursor=; bound time with ?start_time= / ?end_time= (the shorter ?from= / ?to= aliases are also accepted). Add ?interval=1m to return the latest snapshot in each epoch-aligned bucket; supported units are s, m, h, and d, from one second through one day. Omit it, or useraw / tick, for every captured change. Sports depth is forward-captured: the Polymarket archive starts 14 April 2026 and the Kalshi archive starts 12 June 2026.
Games and resolved market context
/v3/sports/{league}/gamesLive games and scores for a league (e.g. nba, nfl, soccer/eng.1), each with its linked Polymarket & Kalshi markets.
/v3/sports/games/{game_slug}The joined game document: schedule and final score, linked prediction markets and settlements, sportsbook lines, and injury context. Use the companion routes below when you need an individual high-volume layer.
/v3/sports/games/{game_slug}/markets/v3/sports/games/{game_slug}/lines/v3/sports/games/{game_slug}/box/v3/sports/games/{game_slug}/plays/v3/sports/games/{game_slug}/winprobGame markets, line movement, box scores, play-by-play, and per-play win probability.
/v3/sports/markets/{condition_id}One normalized market with venue identifiers, outcomes, token IDs, game join, and settlement state.
Players, props, and injuries
/v3/sports/{league}/playersSearch the league athlete directory and retrieve stable athlete IDs used by player-prop joins.
/v3/sports/players/{athlete_id}/v3/sports/players/{athlete_id}/injuries/v3/sports/players/{athlete_id}/box/v3/sports/players/{athlete_id}/marketsPlayer profile, injury change-log, box-score game log, and entity-resolved prediction-market props.
/v3/sports/{league}/injuriesThe live injury feed per league — the pre-game status changes that move the market.
Sportsbook odds
/v3/sports/odds/linesLive moneyline, spread, total, and prop lines across books, normalized for comparison with the market price.
/v3/sports/odds/booksThe active sportsbook catalog and source freshness.
/v3/sports/{league}/odds-historyHistorical sportsbook lines, including NFL history to 1999 and European soccer to the 2000/01 season. Bound NFL requests with season, team, from, or to. Soccer requests require a football-data season code (for example 2324) and/or team.
/v3/sports/odds/streamServer-Sent Events for changing sportsbook lines. Send Accept: text/event-stream; events pass through as they arrive and the connection remains open. Sports order books use the main DepthFeed WebSocket below.
Injury webhooks
/v3/sports/webhookspaid planRegister an HTTPS receiver with league and injury-status filters. The signing secret is shown once. Deliveries include X-DepthFeed-Event and X-DepthFeed-Signature; verify the HMAC-SHA256 signature over the exact raw request body before parsing JSON.
curl -X POST "https://api.depthfeed.com/v3/sports/webhooks" \
-H "Authorization: Bearer df_your_key" -H "Content-Type: application/json" \
-d '{"url":"https://example.com/depthfeed","leagues":["nba","nfl"],"statuses":["out","questionable"]}'/v3/sports/webhookspaid plan/v3/sports/webhooks/{sub_id}/testpaid plan/v3/sports/webhooks/{sub_id}paid planList subscriptions and delivery health, send a signed test event, or revoke a subscription.
# discover a market, then pull its live book
curl "https://api.depthfeed.com/v3/sports/markets?league=mlb&limit=1" -H "Authorization: Bearer df_your_key"
# take tokens[0] from the response, then:
curl "https://api.depthfeed.com/v3/sports/books/<asset_id>/latest" -H "Authorization: Bearer df_your_key"Live stream (WebSocket)
/v3/streamA WebSocket that pushes live order books and prices as they change. Frame payloads are the same JSON objects the REST snapshot endpoints return, so code written against REST transfers directly. Authenticate at connect time with the X-API-Key header, Authorization: Bearer, or — for browsers, which cannot set WebSocket headers — ?api_key=df_….
# wscat -c "wss://api.depthfeed.com/v3/stream?api_key=df_your_key"
> {"op":"subscribe","channels":["book:polymarket:btc:2510645","price:btc"]}
< {"op":"subscribed","channels":[…],"active":2}
< {"channel":"price:btc","data":{"coin":"btc","price":63560.1,…},"ts":1781300671083}
< {"channel":"book:polymarket:btc:2510645","data":{…same shape as REST snapshot…},"ts":…}Channels
| Channel | Payload | Notes |
|---|---|---|
book:polymarket:<coin>:<market_id> | REST snapshot object (with orderbooks) | Tick-level via our CLOB websocket tap |
book:kalshi:<coin>:<ticker> | Same shape as /v3/kalshi/…/snapshots rows | Updates from the paced Kalshi polling loop |
book:limitless:<coin>:<slug> | Same shape as /v3/limitless/…/snapshots rows | Push-based (socket.io tap) |
book:binance:<coin>:<spot|futures> | Same shape as /v3/…/latest | 100ms depth feed |
book:sports:polymarket:<token_id> | Full sports ladder | Quant+: first-party, event-driven CLOB stream |
book:sports:kalshi:<ticker> | Full sports ladder | Quant+: best-effort Kalshi order-book delta websocket, relay fallback; change-only frames |
price:<coin> | { coin, price, source, venue, id, time } | Binance underlying, ~4 ticks/s max |
Ops: subscribe · unsubscribe (each takes {"channels":[…]}, applied atomically) and ping → pong. A trailing * market segment (e.g. book:kalshi:btc:*) subscribes a whole venue/coin — Desk plan only. Op-level problems (bad channel, over your subscription cap) come back as {"op":"error","code":…} frames and never drop the connection.
Sports channels use concrete identifiers and do not support wildcards. Quant, Research, and Desk allow one, two, and three concurrent sports books respectively. Every sports frame includes the complete ladder, venue, asset_id, exchange/receive timestamps, full_ladder: true, and adelivery field naming the source of each frame: polymarket_clob_ws,kalshi_orderbook_delta_ws, or scoretape_relaywhen the sports relay is serving. Kalshi sports books are driven by the authenticated Kalshi order-book delta websocket, with the relay as fallback, so frame timing follows exchange activity rather than a fixed polling interval. Read freshness from each observation's timestamps rather than assuming a refresh rate.
> {"op":"subscribe","channels":[
"book:sports:polymarket:<token_id>",
"book:sports:kalshi:<market_ticker>"
]}
< {"op":"subscribed","channels":[…],"active":2}Per-plan limits
| Plan | Connections | Subscriptions | Channels |
|---|---|---|---|
| Explorer | 1 | 1 | BTC — Polymarket + Binance books + price |
| Quant | 1 | 5 | Every venue, all coins; 1 sports book |
| Research | 2 | 25 | Every venue; 2 sports books |
| Desk | 5 | 100 | Every venue + wildcards; 3 concurrent sports books |
Close codes & reconnecting
| Code | Meaning |
|---|---|
4001 | Authentication failed (missing / unknown / revoked key) |
4003 | Plan connection limit reached |
4029 | Op flooding — slow down |
1013 | Key verification temporarily unavailable — retry shortly |
The server heartbeats with protocol pings every 25s. Deploys and failovers drop connections by design — treat disconnect → reconnect with exponential backoff (250ms doubling to ~5s) and re-send your subscriptions as the normal lifecycle, not an error path.
Freshness, measured
Median capture→client delivery measured from an external client through our edge: Polymarket ≈10ms (p95 ≈30ms), Binance and Limitless sub-100ms, underlying price ≈110ms. Kalshi follows its REST capture cadence, ≈1s median. Numbers come from deploy/stream_freshness.py runs against production — we publish what we measure, nothing rounder.
Wallet Intelligence
Wallet Intelligence is a read-only research workspace for public Polymarket wallets. Save a watchlist, discover traders from Polymarket's public leaderboard, and review public positions, recent activity, realized samples, and portfolio-level metrics in one place. It never connects a wallet, signs a transaction, or places a real order.
Next-book execution audit
For each eligible public trade, DepthFeed finds the first Polymarket book it recorded after the activity timestamp, walks the displayed ladder for the same number of shares, and reports the replay price, fillable fraction, observed delay, and signed price difference versus the public trade. The lookup window is 90 seconds. A missing match is shown as missing; it is never estimated.
Grades are mechanical: Depth remainedmeans at least 95% of the public size was displayed within 1¢ of the trader's price; Price moved means at least 95% remained but at a difference above 1¢; Size unavailable means less than 95% of the public size was displayed.
Forward paper copy
Start a paper mirror from any inspected wallet. Only public trades observed after the mirror is created are eligible: DepthFeed deduplicates each fill, applies the configured copy ratio and per-trade cap, then fills it at the next available live quote in the normal Paper Trading ledger. Cash, positions, P&L, the equity curve, circuit breaker, and settlement history appear under Paper Trading.
An optional HTTPS callback receives each successful copied fill. Its signing secret is shown once. Verify HMAC-SHA256(timestamp.body) against x-depthfeed-signature; the timestamp is sent in x-depthfeed-timestamp. Local, private-network, credential-bearing, non-HTTPS, and redirect destinations are rejected.
| Plan | Saved wallets | Audited trades per refresh | Public activity rows |
|---|---|---|---|
| Explorer | 1 | 3 | 30 |
| Quant | 5 | 10 | 100 |
| Research | 10 | 25 | 250 |
| Desk | 20 | 50 | 500 |
Interpretation limits
- A public address may be only one wallet in a trader's portfolio and does not prove identity or ownership.
- Public activity timestamps are not private order timestamps. The audit measures what DepthFeed observed after publication, not the trader's original latency.
- Only trades in DepthFeed's recorded Polymarket coverage can be matched. Unsupported or uncaptured markets are shown without an audit.
- The replay consumes displayed size mathematically; it cannot model hidden liquidity, queue priority, cancellation races, fees, or the market impact of a real follower order.
- Leaderboard rank, P&L, positions, and activity come from Polymarket's public data services and may be delayed, revised, incomplete, or temporarily unavailable.
- Wallet Intelligence and its paper mirror are research tooling—not live copy trading, investment advice, a recommendation, or a guarantee of execution.
Wallet research guides
Start with the Polymarket wallet tracker guide, then compare wallet analytics, leaderboard research, and copy-trading execution analysis.
Backtest Lab
The Backtest Lab (in your dashboard) backtests entry/exit strategies on resolved native Polymarket, directional Kalshi, and Limitless crypto markets — settlement-anchored, so every simulated trade has a known outcome. It runs on the same order-book history the API serves, within your plan's history window.
Venues and sampling
Polymarket supports 5m, 15m, 1h, 4h and 24h windows. Limitless supports captured 5m and 15m up/down contracts. Kalshi supports the captured directional 15m, 1h and 24h series; range buckets are excluded because YES does not mean UP. Kalshi defaults to one representative directional contract per event so a ladder of correlated strikes is not counted as independent evidence. Advanced users can inspect all strikes with an explicit correlation warning.
Strategies
Five built-in presets (late-favorite, spot-leads, dip-reversion, level-cross, cheap-lotto) plus a custom JavaScript editor: your script plans entries over each market's price path and runs sandboxed in a web worker — no network, hard time budget, stored locally in your browser and exportable as JSON.
Fill models
| Model | Entry price |
|---|---|
| Mid | The snapshot mid — fastest, most optimistic. |
| Mid + slippage | Mid shifted by a fixed slippage you set. |
| Book-depth VWAP | Walks the real ask ladder level by level. Missing or one-sided depth is unfillable; it never falls back to a modeled midpoint. |
Fees are included in sizing and net P&L. Polymarket and Limitless use an editable flat per-share assumption; Kalshi uses its non-linear expected-earnings formula with an editable rate and cent rounding per order.
Portable exports
Export the complete trade log as CSV, the strategy and execution assumptions as portable JSON, or a reproducible run bundle containing the exact tested sample, statistics, risk report, equity curve and trades. Exports never embed raw historical paths or order-book archives.
Position sizing
How much each trade stakes — a flat amount, or a fraction of a compounding bankroll:
| Scheme | Stake per trade |
|---|---|
| Fixed | A flat dollar amount — simple, but the only scheme that can trade a bankroll to zero. |
| Fractional | A constant fraction of your live bankroll (fixed-fractional). It compounds and can't reach zero from sizing alone. |
| Kelly | Growth-optimal f* = (q − p)/(1 − p) for a $1 binary at price p, scaled by a fractional-Kelly multiplier (half-Kelly = the standard hedge) and capped per trade. The win probability q comes from a fixed edge, a fixed win probability, or the strategy's own trailing hit rate. No edge (f* ≤ 0) ⇒ the entry is skipped. |
Risk of ruin
Every run reports a risk panel derived from its own trades: the optimal fraction your edge can support (Ralph Vince optimal-f), a recommended max (half of it), a Monte-Carlo risk of ruin (the chance the bankroll ever falls to ≤30% of its start), and an over-bettingwarning when you're staking past the growth-optimal point — where more risk buys less long-run growth. Deploying to paper auto-caps the live per-trade size at this safe fraction.
Results: trade log, win rate, ROI, Sharpe, max drawdown, the equity curve, and the risk-of-ruin panel. Paid plans can save up to 50 frozen runs (they re-render identically later, no data re-reads), and the built-in AI assistant helps write and debug strategies and interpret sizing and risk within a plan-metered allowance.
Paper trading
Paper Trading runs strategies forward on livemarkets with virtual cash. Fills, marks and settlement are all priced from DepthFeed's live order books — buys at the ask, sells at the bid, positions settle to $0/$1 automatically when the market resolves. Each strategy gets its own equity curve, positions view, and full trade log.
Three ways to trade
| Mode | How it works |
|---|---|
| Webhook | Your own system (bot, cron, notebook) POSTs buy/sell signals to a per-strategy token URL. Your logic stays yours — we do execution, accounting and charts. |
| Lab rule | Deploy a Polymarket or Kalshi Backtest Lab preset (time-window entry, level cross, dip reversion) with venue-native sides, take-profit/stop-loss, a max-open cap, and position sizing (fixed / fractional / Kelly); it's evaluated server-side against live quotes (~90s cadence). |
| Wallet copy | Mirror new public fills from an inspected Polymarket wallet with a copy ratio and per-trade cap. Results use the same paper ledger and may optionally emit signed HTTPS fill webhooks. |
Signal webhook
/paper/hook/{token}no authThe token (shown once at create/rotate) is the auth. Fills always price from the live book at signal time — a payload can never set its own price. Markets are identified by venue + market: a Kalshi ticker, or a Polymarket CLOB token id. You can trade any market on the venue, not just the ones DepthFeed records — if we don't have it locally, the fill is priced from a live read of the venue's own order book.
curl -X POST 'https://api.depthfeed.com/paper/hook/pt_your_token' \
-H 'content-type: application/json' \
-d '{
"action": "buy", # buy | sell | close
"venue": "polymarket", # polymarket | kalshi
"market": "1234567890...", # CLOB token id / Kalshi ticker
"side": "yes", # kalshi: yes|no (polymarket tokens are one-sided)
"usd": 100, # size by dollars… or "shares": 150
"client_id": "sig-0042" # optional idempotency key (safe retries)
}'{ "data": { "filled": true, "action": "buy", "price": 0.62,
"shares": 161.29, "cost_cents": 10000, "cash_cents": 990000,
"position_id": "…" } }| Error | Meaning |
|---|---|
NO_FRESH_QUOTE | No live book for that market — a bad id, or the market has closed / gone one-sided at 0/1 (settlement closes positions automatically). |
INSUFFICIENT_CASH | The order exceeds the strategy's paper cash. |
NO_POSITION | sell/close with no open lot on that market/side. |
RATE_LIMITED | Over 120 signals/min for the strategy. |
PAUSED | The strategy is paused in the dashboard. |
Circuit breaker
Each strategy has a trailing max-drawdown stop (default 60%, editable; set to 0 to disable). If live equity ever falls that far below its high-water mark, the strategy is automatically flattened at current marks and halted — a hard stop against a strategy trading itself toward zero. Resume it any time; resuming resets the high-water mark to your current equity.
Limits
Concurrent strategies per plan: Explorer 1 · Quant 5 · Research 15 · Desk 40. Up to 100 open positions per strategy; starting balance $100–$1,000,000 (default $10,000). Marks refresh on a ~90-second cadence — this is a forward-testing tracker, not an execution venue.
Venues & coverage
Precision comes from sourcing the same upstreams the markets use, so values match by construction.
| Venue | Capture | Windows | Notes |
|---|---|---|---|
| Polymarket | CLOB websocket — every book + price-change event | 5m · 15m · 1h · 4h · 24h | Full depth, event-driven. Settlement open/close from Polymarket's own metadata. |
| Kalshi | Public REST, paced full-depth polling | 15m · 1h · 24h · 1w | Yes/no book, up to 100 levels/side, 7 assets; effective cadence varies with market load and API limits. |
| Limitless | socket.io websocket (orderbookUpdate) | 5m · 15m | CLOB on Base; live push captures the fast 5m books REST can't snapshot. |
| Binance | spot + futures @depth20@100ms + @aggTrade | — | Underlying book + 1s OHLCV, the precision anchor for the up/down markets. |
All 7 assets (btc · eth · sol · xrp · doge · bnb · hype) across every venue that lists them.
Data model & schema
Timestamps are epoch-millis. exch_ts_ms = exchange time, recv_ts_ms = our receive time (the difference is capture latency). These are the fields every order-book snapshot returns over the API.
polymarket_book — full order-book snapshots
asset_id, condition_id, slug, base_asset, market_type, exch_ts_ms, recv_ts_ms, hash, bid_prices[], bid_sizes[], ask_prices[], ask_sizes[]
polymarket_changes — deltas for replay between snapshots
asset_id, condition_id, exch_ts_ms, recv_ts_ms, side, price, size
polymarket_markets — one row per token
asset_id, market_id, event_id, condition_id, slug, outcome, base_asset, market_type, clob_token_up, clob_token_down, resolution_source, start_time, end_time, first_seen_ms
polymarket_reference — settlement
slug, base_asset, market_type, start_ms, end_ms, price_to_beat, final_price, winner, final_volume, final_liquidity, resolved_at, captured_ms
binance_book — 20-level book (spot & futures)
venue, symbol, exch_ts_ms, recv_ts_ms, bid_prices[], bid_sizes[], ask_prices[], ask_sizes[]
binance_trades_1s — 1s OHLCV
venue, symbol, second_ms, open, high, low, close, volume, buy_volume, sell_volume, trades, recv_ts_ms
prices — unified underlying-price series
asset, source (binance|chainlink), venue, exch_ts_ms, price
kalshi_book / kalshi_markets
kalshi_book: ticker, series, base_asset, market_type, recv_ts_ms, yes_prices[], yes_sizes[], no_prices[], no_sizes[]
kalshi_markets: ticker, event_ticker, series, base_asset, market_type, title, status, strike, open_time, close_time, first_seen_ms
limitless_book / limitless_markets
limitless_book: slug, condition_id, base_asset, market_type, recv_ts_ms, midpoint, bid_prices[], bid_sizes[], ask_prices[], ask_sizes[]
limitless_markets: slug, condition_id, base_asset, market_type, title, status, expiration_ms, first_seen_ms
History & coverage
Every plan window is served from the live store plus the cold archive, so the full window is always available. Desk has no rolling history cap: it can query every recorded snapshot from the applicable series floor through the live feed. The floors differ because contracts and licensed capture did not begin on the same day for every asset/window combination.
Polymarket full-depth archive floors (UTC)
| Assets | 5m | 15m | 1h | 4h | 24h |
|---|---|---|---|---|---|
| BTC | 2026-02-12 | 2026-01-01 | 2026-01-01 | 2026-01-01 | 2026-01-01 |
| ETH, SOL, XRP | 2026-02-18 | 2026-01-01 | 2026-01-01 | 2026-01-01 | 2026-01-01 |
| BNB | 2026-03-13 | 2026-03-13 | 2026-03-06 | 2026-03-13 | 2026-03-07 |
| DOGE | 2026-03-13 | 2026-03-13 | 2026-03-11 | 2026-03-13 | 2026-03-11 |
| HYPE | 2026-03-13 | 2026-03-13 | 2026-03-06 | 2026-03-13 | 2026-03-07 |
These are the earliest days with recorded full ladders, not a claim that every asset/window existed before its floor. A snapshot returns the complete recorded ladder; it can legitimately contain no levels when the market itself had no resting orders at that instant.
Kalshi archive floors (UTC)
Kalshi floors are separate from the Polymarket ones above and are later. The earliest recorded Kalshi ladder of any series is 2026-01-08. For the 15-minute crypto series:
| Series | Earliest recorded ladder |
|---|---|
| KXBTC15M, KXETH15M | 2026-01-08 |
| KXSOL15M | 2026-01-09 |
| KXXRP15M | 2026-02-11 |
| KXBNB15M, KXDOGE15M | 2026-03-07 |
| KXHYPE15M | 2026-03-18 |
Hourly, daily and weekly Kalshi series carry their own per-series floors, and BTC, ETH, XRP and DOGE begin on 2026-01-08 there too. Rather than publish a floor per series, treat discovery as authoritative: /v3/kalshi/markets?series=KXBTC15M&start_time=…&end_time=… lists exactly the tickers whose depth is retrievable in that range, and Kalshi ticker ids are venue-defined, so they must be discovered rather than constructed from UTC timestamps.
Kalshi capture cadence and depth are not constant across the archive. Current capture polls the full ladder at up to 100 levels per side every few seconds; earlier periods are sparser, and some spring 2026 days carry only a handful of observations per contract. Snapshot rows are stored as recorded, so a research pull spanning the archive should resample onto a fixed grid and carry an observation count per bucket rather than assume a constant sampling interval.
Order-book depth is captured live and cannot be recreated after the fact. Archive access is delivered through the documented metered query surfaces; DepthFeed does not provide customer-requested reconstruction or bulk archive delivery.
Code examples
Walk a market's full depth history (Python)
import requests
BASE = "https://api.depthfeed.com/v3"
H = {"Authorization": "Bearer df_your_key"}
# 1. find a market
m = requests.get(f"{BASE}/btc/markets?type=15m&limit=1", headers=H).json()["data"][0]
mid = m["market_id"]
# 2. page through its order-book snapshots
cursor, rows = None, []
while True:
q = f"{BASE}/btc/markets/{mid}/snapshots?include_orderbook=true&limit=1000"
if cursor: q += f"&cursor={cursor}"
page = requests.get(q, headers=H).json()
rows += page["data"]
if not page["pagination"]["has_more"]: break
cursor = page["pagination"]["next_cursor"]
print(len(rows), "snapshots")Latest cross-venue depth for BTC up/down (JavaScript)
const h = { Authorization: "Bearer df_your_key" };
// One call → the full BTC 15m book on all three venues at once.
// (No stitching: the screener is the cross-venue entry point.)
const res = await fetch("https://api.depthfeed.com/v3/screener/btc/15m", { headers: h }).then(r => r.json());
const { books } = res.data; // books.polymarket / books.kalshi / books.limitlessAI agents & LLMs
DepthFeed is built to be driven by agents: plain JSON over HTTPS, one Bearer key, stable error codes, and no SDK required. A machine-readable product summary lives at /llms.txt.
As a function-calling / MCP-style tool
Wrap any endpoint as a tool — the API is self-describing enough that one generic definition covers most workflows:
{
"name": "depthfeed_get",
"description": "Query DepthFeed prediction-market order-book data. Paths: /v3/{coin}/markets, /v3/{coin}/markets/{id}/snapshots, /v3/kalshi/markets, /v3/kalshi/{ticker}/snapshots, /v3/kalshi/{ticker}/candles, /v3/limitless/{slug}/snapshots, /v3/{coin}/{spot|futures}/latest. Coins: btc eth sol xrp doge bnb hype.",
"parameters": {
"type": "object",
"properties": { "path": { "type": "string", "description": "GET path under /v3, with query params" } },
"required": ["path"]
}
}The tool body is a single authenticated GET:
curl "https://api.depthfeed.com{path}" -H "Authorization: Bearer df_your_key"Live data in agents
The WebSocket stream uses three JSON ops (subscribe / unsubscribe / ping) and authenticates with ?api_key=where headers can't be set — trivial to drive from any runtime. Frames carry the same JSON objects as REST, so an agent's parsing code is identical for history and live.
/v3/whoamiechoes the key's plan, rate limits, and history window — call it first and self-configure instead of guessing limits.Status & changelog
What's live, newest first:
- Live streaming.
/v3/streamWebSocket — order-book and price channels on every venue, ~10ms median Polymarket delivery, plan-gated subscriptions. - Limitless venue. Markets, latest orderbook, and historical depth snapshots — with 5m + 15m captured live over the order-book websocket.
- Kalshi expanded. 21 series for all 7 assets (15-minute, threshold, and directional — the latter two running hourly/daily/weekly concurrently);
market_typeexposed and filterable. - Full v3 API. Polymarket markets + snapshots, Binance spot/futures, batch, cursor pagination, per-plan history enforcement, metered usage.
- Public HTTPS.
https://api.depthfeed.comover TLS.
Order-book depth fills forward from capture start and cannot be back-filled — history matures toward your plan window over calendar time. Questions or a backfill request? Get in touch.