vike
Concepts

Polymarket data model

What the Polymarket endpoints and the archive record: market and token ids, event rows, order-book snapshots and the on-chain settlement.

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.

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.

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 (about 2,134 markets when measured on 2026-09-03). So [] means "the chain resolved nothing", never "still open". For "how did this end", the settlement is the authority.

On this page