Guides / API Guide
There is no "give me the book at exactly 14:32:07" endpoint. The historical orderbook endpoints are range queries, so a point-in-time lookup is a narrow range plus a choice about which side of the target to take. That choice matters more than it looks.
Ask for a window bracketing your target and take the nearest snapshot:
# target 2025-01-20T00:00:00Z = 1737331200
GET /v1/historical/polymarket/orderbook
?market_id=<market_id>
&granularity=1m
&start_time=1737331140 # target - 60s
&end_time=1737331260 # target + 60s
&limit=10
Size the window to the granularity you requested. At 1m, ±60s reliably
contains at least one snapshot; at 5m, use ±300s. A window narrower than the
sampling interval can legitimately return zero rows.
For anything resembling a backtest, use the last snapshot at or before the target timestamp, not whichever is closest. The nearest snapshot may be after your decision point, which means your strategy is reading a book that had not formed yet — a subtle look-ahead bias that quietly flatters results.
snapshots = res["snapshots"]
before = [s for s in snapshots if s["timestamp"] <= target]
book = max(before, key=lambda s: s["timestamp"]) if before else None
Resolving a thousand timestamps with a thousand ±60s requests is the fastest way to hit
rate limits. Pull the whole range
once, sort by timestamp, and resolve every target locally with a binary search.
One request covering an hour beats sixty covering a minute each.
Each snapshot carries timestamp, the depth arrays
(bids/asks on Polymarket, yes_bids/no_bids
on Kalshi), and the derived best_bid, best_ask, mid,
and spread. If you only need top-of-book, the derived fields save you walking
the arrays.
Data from Kalshi and Polymarket. Search live API docs Pricing