vike

Polymarket internals

What the Polymarket endpoints and the archive record: market and token ids, recorded and catalog markets, event rows, order-book snapshots, top-of-book quotes, the on-chain settlement and the trade tape behind the trader routes.

The Polymarket CLOB here is recorded by Vike, not a proxy of Polymarket's own API, and settlement comes from the chain. These are the rules that hold across the endpoints and the bulk archive.

Identifiers

Two different ids appear in this namespace and they are not interchangeable.

  • condition_id — a 0x-prefixed hex string identifying a market. It is what /markets/{condition_id} and /settlements/{condition_id} take in the path.
  • token_id — a long decimal string identifying one outcome token. A binary market has two, returned in token_ids. It is what the per-token endpoints take: /market_stats, /ohlcv, /orderbook and /events.

Get both from /markets.

Recorded and catalog markets

/markets lists the markets Vike records, and the recorder discovers active markets only, so that directory is a subset of every market Polymarket has listed. /markets/{condition_id} answers beyond it: a market the directory does not hold is looked up in Polymarket's full market catalog, and every row the route returns carries source, "recorded" or "catalog". A catalog row has tick_size and neg_risk as null, because the catalog has neither, and active/closed derived by the same rule as a recorded row. Whether a token has a recorded tape is what /market_stats answers.

Settlement rows take their market fields (slug, token_ids, outcomes, question) from that same full catalog, not from the recorded directory. market_known says whether the catalog has the market at all: when it is false those fields are empty, and the on-chain fields are still exact.

Coverage: the recording starts 2026-07-25

The recorded book, which /events, /orderbook, /market_stats and /ohlcv read and the bulk archive publishes, starts on 2026-07-25. The book event tape and the top-of-book quotes are not pruned, so that first day stays available as new days are added.

When the request alone shows why an answer is empty, the response carries the reason in an X-Vike-Note header and the body is unchanged:

RequestX-Vike-Note
/events, /orderbook or /ohlcv whose window ends (to_ms, ts, to) before 2026-07-25Polymarket L2 data starts 2026-07-25
/ohlcv with from after to (when to is also before 2026-07-25, only the 2026-07-25 note is sent)from is after to
/markets/{condition_id} or /settlements/{condition_id} with a value that is not 0x and 64 hex digitscondition_id is 0x followed by 64 hex digits; this value is not one

Any other empty answer carries no header: an unknown id, a window outside one token's recorded span, a filter nothing matches.

Event rows

These notes are about the rows /events returns.

bids and asks are JSON-encoded strings, not arrays

The bids and asks fields hold JSON text, not arrays: "bids": "[[0.782,0.0]]" must be parsed a second time to become [[0.782, 0.0]], and an event that carries no book side sends the empty string "" rather than null or [].

Unpopulated numeric fields are 0, not null

A zero in an event row is usually absent data. A price_change row carries "best_ask": 0 and "best_bid": 0 — that is "this event type does not populate the field", not "the best bid is zero". status is "" for the same reason. Read fields according to event_type; do not treat a zero here as a price.

Book snapshots repeat rows and may lack a side

These notes are about /orderbook.

The same (side, level) can arrive several times — de-duplicate before summing size

The repeats are byte-identical rows, they are not extra depth, and a client that sums the raw array overstates the book several-fold: de-duplicate on (side, level) first. The multiplier is per-token and is not stable over time, so do not code against a fixed factor: twelve tokens sampled in one minute on 2026-09-03 returned factors of 1 (no duplication at all), 2, 5, 9 and 11, and the token that returned 6 copies per level on 2026-09-02 returned 9 the next day. Every row in a response shares a single as_of_ts: the recorder writes several snapshot rows that carry the same venue timestamp, and /orderbook returns all of them, so the repeats are one moment fanned out, not successive ones. Read the depth of a side as its max(level), never as a row count.

A snapshot's rows come in a fixed order. Asks, when a snapshot has them, come first in the array (the side column sorts alphabetically, ask before bid), then the bids, each ascending by level. Do not assume a response contains both sides: group by side and handle an absent one, which matters to any client computing a spread.

Top-of-book quotes

The l1_quotes stream is top of book derived from the recorded book: bid, ask, bid_size and ask_size per token, one row per change. It is published as archive files only; no endpoint returns its rows. The feed is event-driven, so a stretch with no rows means the top of book did not move, not that recording stopped. Two trader routes price from it: /wallets/{address} marks an open position at the token's latest quote within the last seven days, and the mispricings of /smart_money measure cohort entries against the current mid.

Settlement is chain truth

Settlement is chain truth; the market row may disagree

/settlements/{condition_id} is the on-chain resolution, not the market's own lifecycle flags, and the two agree in one direction only. /markets/{condition_id} derives closed from on-chain resolutions plus the venue's own closed flag, so a market with a settlement row reads closed: 1 there. The reverse does not hold: a market the venue closed without the chain ever resolving it — a cancellation or an oracle void — is closed: 1 in the directory and [] from the settlements route. So [] means "the chain resolved nothing", never "still open". For "how did this end", the settlement is the authority.

For many markets at once, /settlements/bulk returns the same row, oldest resolution first, up to 5,000 to a page, filtered by resolution time (from_ms inclusive, to_ms exclusive) and slug_prefix. Walk it by passing each page's next_cursor back as cursor until has_more is false. A market with no known slug never matches a prefix, and a market the chain never resolved is not listed.

The trader routes read the trade tape, not the book

/wallets/{address}, /smart_money and /leaderboard run the same code as the MCP tools polymarket_wallet, polymarket_smart_money and polymarket_leaderboard. Their volumes, trade counts and P&L come from aggregates of the on-chain trade tape (wallet P&L, the smart-money cohort, the hourly wallet leaderboard), not the recorded L2 book; only the open-position marks and the mispricing mids come from the top of book. So a volume or a trade count from them is not comparable to one from /market_stats, /ohlcv or /events. That tape starts on 2026-01-01, earlier than the recorded book.

On this page