File schemas
Two container formats, and two venues that do not share a field list. Everything below is a column or key you will actually find in a file, listed per dataset.
The two formats
Settlement feeds and klines are gzipped CSV with a header row. Market event streams are gzipped JSONL — one JSON object per line, in the order the frames arrived. Nothing is re-sorted on the way into the archive.
Settlement feeds — CSV (Polymarket side)
The same five columns for prices, twap30s and twap60s. This is the only place in the archive where three separate timestamps travel together.
| feed_ts_ms | Event time: the timestamp upstream put on the report (UTC ms) |
| value | Price as a float, for convenience |
| full_accuracy_value | Whenever the relay publishes it, the same price as a fixed-point integer string (1e18). Use this to recompute outcomes, not value |
| server_ts_ms | When the upstream server sent it (UTC ms) |
| recv_ms | When we received it (UTC ms). All three are kept apart, never merged — so you can measure the capture path |
Market events — the JSONL envelope (Polymarket side)
Every line in book, price_change, best_bid_ask and last_trade_price carries the same six top-level keys. Note there are TWO timestamps here, not three, and the event one is not called feed_ts_ms.
| slug | The market this frame belongs to |
| asset_id | Which outcome token the frame is about. Null on price_change, because one of those lines carries the changes for both sides at once |
| event_type | Same name as the dataset |
| event_ts_ms | Upstream event time (UTC ms) |
| recv_ms | When we received it (UTC ms) |
| payload | The upstream message, kept as it arrived |
What is inside payload, per dataset
| book | bids and asks, each an array of {price, size} objects, plus hash, market, asset_id and timestamp. One line is a snapshot of ONE outcome token — which one is the envelope asset_id — and carries both of its ladders. An empty array means that ladder holds no orders, not that it went unreported |
| price_change | price_changes, an array whose items each carry hash, side, size, price, asset_id, best_ask and best_bid. Both outcome tokens appear in the same line, which is why the envelope asset_id is null |
| best_bid_ask | best_bid, best_ask and spread, for one asset_id. Prices only — there are no sizes on this stream, so depth still comes from book or price_change |
| last_trade_price | side, size, price, fee_rate_bps and transaction_hash, for one asset_id |
markets — one line per market
Metadata, the strike, and the settlement once it exists. The raw key holds the upstream market object unchanged, which is where the settlement configuration lives.
| slug / asset / interval_sec | Identity and duration. interval_sec is seconds |
| condition_id / token_ids | On-chain identifiers. token_ids has two entries and the FIRST is Up — established by measurement, not by assumption |
| start_sec / end_sec | Market window, in SECONDS — not milliseconds like the event streams |
| resolved / outcome_prices | Settlement. ["1","0"] means Up won, ["0","1"] means Down won. Only a complete binary pair is meaningful |
| strike_value | The price to beat, as a fixed-point integer string (1e18). Null when we cannot establish it honestly — never guessed from a nearby tick |
| raw | The upstream market object as received, including raw.cryptoMarketConfig — see how a market settles |
klines — CSV
Derived from the settlement feed, so these are OHLC and there is no volume column. ticks counts settlement updates in the bucket; it is not traded size.
| ts_ms | Bucket start (UTC ms) |
| open / high / low / close | Prices within the bucket |
| ticks | How many settlement updates fell in the bucket — an update count, not volume |
Predict.fun does not share the schema above
Different column names, a different ladder shape, and different time units. If you subscribe to both platforms, treat them as two formats rather than one with extra fields.
| prices (CSV) | price_feed_id, symbol, provider, publish_time, server_ts, price, recv_ms. publish_time and server_ts are in SECONDS while recv_ms is milliseconds, and the price column is called price rather than value |
| orderbook (JSONL) | market_id, category_slug, update_ts_ms, recv_ms, payload. Inside payload, bids and asks are arrays of [price, size] PAIRS — not {price, size} objects as on the Polymarket side — alongside version, orderCount, lastOrderSettled and settlementsPending |
| markets (JSONL) | category_slug, asset, interval_label, market_id, price_feed_id, price_feed_symbol, price_feed_provider, condition_id, start_sec, end_sec, start_price, end_price and status. Prices here are ordinary decimal strings, not 1e18 fixed point |
One thing worth knowing before you write a settlement check against this: status reports what upstream last told us, and a market stops being re-read once its end_price arrives. end_price is therefore the field that tells you a Predict.fun market has settled.
Working with one of these in particular: Polymarket order book data · Chainlink settlement data · Predict.fun historical data · Compared with other providers