Polymarket API — Order Book, Fills & History avatar

Polymarket API — Order Book, Fills & History

Pricing

Pay per event

Go to Apify Store
Polymarket API — Order Book, Fills & History

Polymarket API — Order Book, Fills & History

Live and historical Polymarket data in one normalized schema: market odds, full L2 order-book depth (every bid and ask level with size), executed trades with on-chain transaction hashes, and an archived order book over time for backtesting. No login, no cookies, no account.

Pricing

Pay per event

Rating

0.0

(0)

Developer

Dirtycode

Dirtycode

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

a day ago

Last modified

Categories

Share

Polymarket API — Markets · Order Book · Fills · History

Live and historical Polymarket data in one normalized schema. Market odds, full L2 order-book depth, executed trades with on-chain transaction hashes, and an order-book archive that Polymarket itself does not publish. All public data — no login, no cookies, no account.

Four datasets, priced separately

ModeWhat you getPrice
marketsLive odds across Polymarket$0.005 per market
orderbookEvery bid and ask level with size$0.02 per snapshot
fillsExecuted trades, with on-chain hash$0.002 per trade
historyOur archived order book over time$0.002 per snapshot

You only pay for rows you actually receive.

History — our own archive, and who else has one

Polymarket publishes no historical order book. Once a moment passes, the depth at that moment is gone from the venue, so any archive exists only because someone captured it live.

We are not the only ones who did, and you should know that before you buy. Specialist vendors sell Kalshi and Polymarket order-book history with more depth and finer resolution than this actor: tick-level with millisecond timestamps, delivered as Parquet or queryable via DuckDB and Snowflake, some reaching back years. If you need the deepest or finest historical book available, buy from them — we would rather say so than have you find out after paying.

What this actor is for: the same data through Apify, per row, with no subscription, no sales call and no minimum. That is a convenience and pricing proposition, not a claim to exclusive data.

Exactly what the archive covers

MarketsThe top ~50 Polymarket markets by traded volume, re-selected hourly. A market that slips out of the top stays in the archive until it falls well below it, so series do not break on noise.
Not coveredAnything outside that set. A market ranked ~52 by volume — still tens of millions traded — has no history here at all, and the run will say so.
Starts2026-07-27 19:53 UTC for the current market set. Earlier rows exist but describe a different, badly chosen set of markets; treat 27 July as the start.
Interval5 minutes. An unchanged book is stored once with a widening span, so quiet markets have fewer rows without losing coverage.

Ask for a window before 2026-07-27 and you will correctly get nothing — the coverage block says firstObservedAt so you can check before you build on it. We would rather show you the edge of the archive than let you discover it inside a backtest.

Every history response carries coverage, and this is the point:

FieldWhat it tells you
firstObservedAt, lastObservedAtThe full span we hold for this market — not just your window
gapsEvery real interruption, as from/to/minutes. Empty means continuous.
expectedIntervalMinutesThe cadence we aim to capture at
medianTimeBetweenChangesMinutesHow often this market actually moved
longestStableSpanMinutesLongest stretch the book sat unchanged

Rows are spans, not instants. A book that does not change is stored once: observedAt is when we first saw it, observedUntil when we last saw it still unchanged. On a quiet market those can be half an hour apart with nothing missed.

That distinction is on every row for a reason. If you write your own coverage check, compare the start of each row to the END of the previous one. Comparing consecutive observedAt values reports every quiet stretch as an outage — a mistake this API's own gap calculation made until 2026-07-28, and one an independent reviewer made the same day. You should be able to contradict our coverage claim with the data we hand you; that is the only kind of honesty that means anything for history nobody can re-derive.

A backtest run across a gap you did not know about produces a confident wrong number and the data gets the blame, so you get the holes up front — and the means to check them.

Markets

FieldNotes
question, ticker, urlMarket identity and link (ticker is the slug)
conditionId, tokenIdsThe ids the other three modes take. conditionId for fills; tokenIds[0] — the YES token — for order book and history
yesPrice, noPriceImplied probability, 0..1
volume, liquidityIn USD, unlike Kalshi where volume is contracts
volumeUnit, liquidityUnitAlways usd here. Carried on every row so a cross-venue query cannot silently compare dollars against Kalshi's contracts.
closeTimePolymarket's stated end date. A past date does not mean trading stopped — measured 2026-07-30, 6 of the top 60 had a past end date while still accepting orders, one with 2 bids and 53 asks against $62.6M volume. Trust status.
statusOnly open markets are returned

Not returned here, and stated rather than left for you to discover: spread is always null in this mode — the market listing gives a price, not a book, so the real bid/ask gap comes from orderbook. openInterest is not published by Polymarket at all. resolvedOutcome is always null because we only return open markets.

Order book

Full L2 depth: bestBid, bestAsk, midPrice, spread, lastTrade, plus bids[] and asks[] with price and size. Addressed by CLOB token id.

A book with no bids and no asks is not returned and not charged. An empty book is indistinguishable from a broken parser, so it is reported as a failure rather than billed as a row.

Fills

FieldDescription
side, price, size, valueDirection, price, shares, notional
outcome, assetWhich outcome token changed hands
walletTrader's proxy wallet — the basis for whale tracking
transactionHashVerify any row on-chain yourself
tsVenue timestamp

Each fill carries a summary broken down per outcome, never blended. A single market's trade feed contains both outcome tokens: on one live market the YES fills averaged 0.003 and the NO fills 0.997. A combined average of 0.5 is not a compromise between them — it describes no instrument that exists, and a backtest built on it would be confidently wrong. So there is deliberately no top-level VWAP.

⚠️ Trades come newest-first, so your limit decides how far back you reach. The busiest markets hold well over 10,000 trades; until 2026-07-31 this actor silently returned at most 500 of them. It now pages, and Max results is what bounds it — raise it to go further back. Rows the venue re-serves while paging (a live feed shifts under you) are deduplicated on the on-chain transaction, so summing value over the result does not double-count.

Fills are addressed by market conditionId (the 0x… id), not the CLOB token. Passing the token returns an empty success at the venue rather than an error, so the actor names which identifier it wants when you get it wrong.

Limits, stated up front

  • Two different identifiers. Order book and history take the CLOB token id; fills take the market conditionId. They are not interchangeable.
  • History depth grows forward. The archive starts when our capture started; it does not reach back before that, and no vendor can sell you what was never recorded.
  • Snapshots, not a stream. Each run captures a moment.

Use cases

Backtesting with real depth rather than assumed fills, quant research, whale and wallet tracking, market-making analytics, cross-venue arbitrage against Kalshi, AI agents needing live odds.


For the developer (not shown on the Store)

Thin wrapper over the private scraper-gateway; contains no scraping logic. Set Actor environment variables (secret): SCRGW_URL, SCRGW_SECRET. Pay-per-event events: market-returned ($0.005), orderbook-snapshot ($0.02), fill-returned ($0.002), history-snapshot ($0.002). History requires the gateway to have DATABASE_URL_RO set (read-only role; the collector holds the only write credential). Deploy: apify push --force.