Polymarket historical data: the full L2 order book archive
Every book snapshot, price change and trade the recorder received since 2026-07-25, plus top-of-book quotes: one Parquet file per stream per UTC day, and the same files cut by market family. CC BY 4.0 on a free key; the samples need no key.
“Give me the download link for the BTC 5-minute quotes of 2026-11-02”
polymarket_archive“Which days of the Polymarket archive are the largest, and how big is a day of book_events?”
polymarket_archive- Open a sample
One complete market in all three streams, the same columns as the archive. No key.
- Find the day
/archive/datasetslists every file with its size and, where recorded, its rows. - Download it
/archive/urlwithredirect=truehands you the file; downloads are not counted against your limit.
A day of trades in one command
The same three steps in cURL, Python and the CLI.
curl -O https://data.vike.io/archive/samples/trades.parquet # sample, no key
curl -H "X-API-KEY: $VIKE_API_KEY" \
"https://data.vike.io/v1/polymarket/archive/datasets?stream=trades&from=2026-11-02&to=2026-11-02"
curl -L -o trades-2026-11-02.parquet -H "X-API-KEY: $VIKE_API_KEY" \
"https://data.vike.io/v1/polymarket/archive/url?date=2026-11-02&stream=trades&redirect=true"
import os, requests
import polars as pl
H = {"X-API-KEY": os.environ["VIKE_API_KEY"]}
day, stream = "2026-11-02", "trades"
r = requests.get("https://data.vike.io/v1/polymarket/archive/url",
params={"date": day, "stream": stream, "redirect": "true"}, headers=H, stream=True)
r.raise_for_status()
with open(f"{stream}-{day}.parquet", "wb") as f:
for chunk in r.iter_content(1 << 20):
f.write(chunk)
print(pl.read_parquet(f"{stream}-{day}.parquet").head())
vike-data pm archive --stream trades --date-from 2026-11-02 --date-to 2026-11-02 # the day's files, sizes and rows
vike-data pm archive --view url --stream trades --date 2026-11-02 # a 7-day download link
- Download whole files, then read them locally; do not point a Parquet reader at the remote URL.
- Archive downloads do not count against the hourly limit. The samples and
manifest.jsonneed no key. - A link from
/archive/urlis valid 7 days and needs no key, so do not share it. - Licence CC BY 4.0: use it for anything, credit Vike.
Archive calendar · /archive/datasets
/v1/polymarket/archive/datasets?limit=1000Which file to take
l1_quotes if top of book is enough, trades for the tape, book_events for full depth: the other two derive from it and are far smaller.
| File | A day’s file, average of the last 7 days | What is inside | Take it for |
|---|---|---|---|
l1_quotes | best bid and ask with sizes, one row per change | prices, spreads, a backtest on top of book | |
trades | the taker prints | volume, the tape, buy and sell pressure | |
book_events | full L2: snapshots, deltas, trades, markers | rebuilding the book at any moment, depth, slippage |
Top-of-book quotes
Derived top of book — bid, ask and both sizes, one row per change.
- Route
GET /v1/polymarket/archive/url- Cadence
- One partition per UTC day
- Coverage
- Archive only: l1_quotes.parquet per UTC day from 2026-07-25 (CC BY 4.0), derived from book_events and published separately because it is far smaller. Resolve a file with /archive/url (redirect=1 for a 302); /archive/datasets lists every partition with its size and, where recorded, its row count.
- Rows
Fields
| Field | Type | Description |
|---|---|---|
token_id | String | The outcome token |
condition_id | String | The market, 0x-prefixed |
ts | Int64 | Quote time, epoch milliseconds |
local_ts | Int64 | Receive time, epoch milliseconds |
bid | Decimal(9, 4) | Best bid |
ask | Decimal(9, 4) | Best ask |
bid_size | Decimal(18, 6) | Shares at the best bid |
ask_size | Decimal(18, 6) | Shares at the best ask |
Real rows
Top-of-book quotes · rows
Load it
curl -H "X-API-KEY: $VIKE_API_KEY" \
"https://data.vike.io/v1/polymarket/archive/datasets?limit=1000"
# Full history is the Parquet archive. Pick a date from manifest.json (no key needed),
# download the whole file, then read it locally:
DAY=YYYY-MM-DD
curl -H "X-API-KEY: $VIKE_API_KEY" -O \
"https://data.vike.io/archive/venue=polymarket/date=$DAY/l1_quotes.parquet"
# Or the free sample — one complete market, no key:
curl -O https://data.vike.io/archive/samples/l1_quotes.parquet
import os, requests
import pyarrow.parquet as pq
H = {"X-API-KEY": os.environ["VIKE_API_KEY"]}
day = "YYYY-MM-DD" # any date listed in https://data.vike.io/archive/manifest.json
url = f"https://data.vike.io/archive/venue=polymarket/date={day}/l1_quotes.parquet"
# Download the whole file once, then read it locally — a remote Parquet
# reader re-fetches the footer and column chunks on every query.
with requests.get(url, headers=H, stream=True, timeout=600) as r:
r.raise_for_status()
with open("l1_quotes.parquet", "wb") as f:
for chunk in r.iter_content(1 << 20):
f.write(chunk)
table = pq.read_table("l1_quotes.parquet")
print(table.num_rows, table.schema.names)
import polars as pl
df = pl.read_parquet("l1_quotes.parquet") # downloaded first — see the cURL tab
df = df.with_columns(pl.from_epoch("ts", time_unit="ms").alias("time"))
spread = (
df.with_columns((pl.col("ask") - pl.col("bid")).alias("spread"))
.group_by("token_id")
.agg(pl.len().alias("changes"), pl.col("spread").mean().alias("avg_spread"))
.sort("changes", descending=True)
)
print(spread.head())
-- l1_quotes.parquet downloaded first (see the cURL tab), then read locally
SELECT token_id,
count(*) AS changes,
avg(ask - bid) AS avg_spread,
epoch_ms(min(ts)) AS first_quote,
epoch_ms(max(ts)) AS last_quote
FROM 'l1_quotes.parquet'
GROUP BY token_id
ORDER BY changes DESC
LIMIT 10;
Download whole files, then read them locally — do not point a Parquet reader at the remote URL. Archive downloads need a key but do not count against the hourly limit.
Full reference for /v1/polymarket/archive/url → · back to the catalog
Order-book events
The full L2 tape — book snapshots, price_change deltas, trades, tick-size and status markers.
- Route
GET /v1/polymarket/events- Cadence
- Continuous; archive one partition per UTC day
- Coverage
- API: /events returns up to 24 hours per call and up to 50,000 events per page (next_cursor + has_more), from 2026-07-25; /orderbook returns the nearest book snapshot at or before any instant from then on, depth up to 25. Archive: book_events.parquet per UTC day from 2026-07-25 (CC BY 4.0), which also carries condition_id and tick_size.
- Rows
Fields
| Field | Type | Description |
|---|---|---|
token_id | string | The outcome token (ERC-1155 id) |
ts | integer | Event time, epoch milliseconds |
local_ts | integer | Receive time, epoch milliseconds |
seq | integer | Feed sequence number |
event_type | string | book | price_change | trade | tick_size_change | status |
is_snapshot | integer | 1 on a full-book row, 0 otherwise |
side | string | none | buy | sell |
price | number | The changed level (price_change) or the print (trade) |
size | number | Shares at that level, or traded |
best_bid | number | Top of book as recorded on the event; 0.0 when not set |
best_ask | number | Top of book as recorded on the event; 0.0 when not set |
bids | string | JSON [[price, size], …] carried as a string; empty when absent |
asks | string | JSON [[price, size], …] carried as a string; empty when absent |
status | string | Marker on status rows, e.g. gap_start; empty otherwise |
Real rows
Order-book events · rows
Load it
# replace each {placeholder} with your own value
curl -H "X-API-KEY: $VIKE_API_KEY" \
"https://data.vike.io/v1/polymarket/events?token_id={token_id}&from_ms={from_ms}&to_ms={to_ms}&event_type=price_change&limit=50"
# Full history is the Parquet archive. Pick a date from manifest.json (no key needed),
# download the whole file, then read it locally:
DAY=YYYY-MM-DD
curl -H "X-API-KEY: $VIKE_API_KEY" -O \
"https://data.vike.io/archive/venue=polymarket/date=$DAY/book_events.parquet"
# Or the free sample — one complete market, no key:
curl -O https://data.vike.io/archive/samples/book_events.parquet
import os, requests
import pyarrow.parquet as pq
H = {"X-API-KEY": os.environ["VIKE_API_KEY"]}
day = "YYYY-MM-DD" # any date listed in https://data.vike.io/archive/manifest.json
url = f"https://data.vike.io/archive/venue=polymarket/date={day}/book_events.parquet"
# Download the whole file once, then read it locally — a remote Parquet
# reader re-fetches the footer and column chunks on every query.
with requests.get(url, headers=H, stream=True, timeout=600) as r:
r.raise_for_status()
with open("book_events.parquet", "wb") as f:
for chunk in r.iter_content(1 << 20):
f.write(chunk)
table = pq.read_table("book_events.parquet")
print(table.num_rows, table.schema.names)
import polars as pl
df = pl.read_parquet("book_events.parquet") # downloaded first — see the cURL tab
df = df.with_columns(pl.from_epoch("ts", time_unit="ms").alias("time"))
print(df.group_by("event_type").len().sort("len", descending=True))
-- book_events.parquet downloaded first (see the cURL tab), then read locally
SELECT event_type,
count(*) AS events,
count(DISTINCT token_id) AS tokens
FROM 'book_events.parquet'
GROUP BY event_type
ORDER BY events DESC;
Download whole files, then read them locally — do not point a Parquet reader at the remote URL. Archive downloads need a key but do not count against the hourly limit.
Full reference for /v1/polymarket/events → · back to the catalog
trades.parquet, the third stream, has its fields, real rows and loading code on the Trades page, beside the on-chain trades with wallets.By day, or by market family
The same recording and the same columns, cut two ways.
| Layout | By day | By market family |
|---|---|---|
| Path | venue=polymarket/date=YYYY-MM-DD/{stream}.parquet | venue=polymarket/asset=<asset>/tenor=<tenor>/date=YYYY-MM-DD/{stream}.parquet |
| For | everything that day | one family without downloading the whole day |
| Families | — | btc, eth, sol, xrp, doge, bnb, hype × 5m, 15m, 4h; other/other holds every other market and is the largest |
| From | 2026-07-25 | 2026-07-26 |
curl -L -o btc-5m-l1.parquet -H "X-API-KEY: $VIKE_API_KEY" \
"https://data.vike.io/v1/polymarket/archive/url?date=2026-11-02&stream=l1_quotes&asset=btc&tenor=5m&redirect=true"
vike-data pm archive --view url --stream l1_quotes --date 2026-11-02 --asset btc --tenor 5m