Schemas Get a free key
Polymarket · Docs

Polymarket API docs

Base URL https://data.vike.io/v1, one header, 16 routes. Every endpoint below with its parameters and a call you can copy in cURL, Python, the CLI or MCP.

Ask your AI · Claude, ChatGPT, CursorConnect in a minute →

“Find the 5-minute BTC market trading now and show its order book”

polymarket_markets polymarket_orderbook

“How did this market resolve, and who held the winning side? (paste a link)”

polymarket_settlement polymarket_market_trades
  1. Sign in at vike.io

    Any account. No card, no plan to pick.

  2. Create a key

    On /account?tab=api-keys. Up to 3 active keys per account; every key starts vk_.

  3. Send the header

    X-API-KEY: vk_… on every request. Or skip the code: vike-data init in the CLI, or connect MCP.

First request

Find a market, then its tokens

Every market carries its condition_id and the token_ids of its outcomes: the two ids every other route takes.

bash
curl -H "X-API-KEY: $VIKE_API_KEY" \
  "https://data.vike.io/v1/polymarket/markets?query=btc-updown-5m&active=true&limit=5"
  • condition_id (0x + 64 hex) names a market; the market routes and settlements take it.
  • token_id (a long decimal) names one outcome; /orderbook, /events, /ohlcv and /market_stats take it.
  • Detail routes answer a bare array: an unknown id is 200 [], not a 404.
  • When the request alone explains an empty answer, the reason is in the X-Vike-Note header.
Limits

Free, with one ceiling per key

Requests20,000 per hour, per key, a rolling hour
Per minute200 per minute, per key, on /v1
KeysUp to 3 active per account; each key is its own budget
Cost of a call1 per REST request; MCP tools 1 or 2
Archive downloadsNot counted against the hourly limit; samples and manifest.json need no key
Price$0, nothing is billed
Try it

Request builder: all 16 routes

Pick a route; the parameters come filled with real ids. The call is rebuilt as you type, and a captured route shows its real answer.

GET
bash
Endpoints

All 16 routes

Click a route to jump to its parameters and a call you can copy.

GET /v1/polymarket/markets List Polymarket markets
GET /v1/polymarket/markets/{condition_id}/trades One market's trades, with wallets (paged)
GET /v1/polymarket/settlements/bulk On-chain settlements (paged)
GET /v1/polymarket/orderbook Order-book snapshot
GET /v1/polymarket/market_stats One token's tape summary
GET /v1/polymarket/ohlcv Polymarket candles
GET /v1/polymarket/events Raw event tape (paged)
GET /v1/polymarket/wallets/{address} One trader's profile
GET /v1/polymarket/wallets/{address}/correlated Wallets that trade the same markets
GET /v1/polymarket/smart_money Smart-money signals
GET /v1/polymarket/leaderboard Wallet leaderboard
GET /v1/polymarket/archive/datasets Archive file index
GET /v1/polymarket/archive/url Resolve one archive file
GET /v1/polymarket/stream-events Stream catch-up
Endpoints

Markets and settlements

Find a market and its outcome tokens, its trades with the wallet behind each, and how the chain resolved it.

Polymarket · REST · CLI · MCP

List Polymarket markets

Search/filter recorded markets. Returns a BARE ARRAY, newest end_date first; page with limit and offset.

Route
GET /v1/polymarket/markets
CLI
vike-data pm markets
MCP
polymarket_markets
Cost
1 request
Free APIArchiveStreamMCP

Parameters

ParameterInDescription
queryqueryCase-insensitive substring match on the market slug.
activequerytrue = only active, false = only inactive, omit = all.
closedqueryThe complement of active: true (or 1) = only closed.
limitqueryMax rows. Default 50, hard cap 100 — a larger value is silently clamped, not rejected.
offsetqueryRows to skip, an integer from 0 to 10000. Default 0. Page with limit and offset; with an offset, rows with the same end_date order by condition_id, so pages do not repeat or skip a market. Above 10000 is a 400.
  • active and closed are derived rather than stored: a market is closed when its on-chain resolution exists or Polymarket's own closed flag says so. ?active=false therefore returns the closed markets, and a settled 5-minute market reports itself settled.
  • ⚠ ?active= is also the SLOW path — ~1.00 s against ~46 ms for an unfiltered page, because a filter on a derived flag has to derive it for every market before it can limit.

Call it

bash
curl -H "X-API-KEY: $VIKE_API_KEY" \
  "https://data.vike.io/v1/polymarket/markets?query=btc-updown-5m&active=true&limit=5"
Polymarket · REST · CLI · MCP

One market

One market by condition_id, as an ARRAY of 0 or 1 rows.

Route
GET /v1/polymarket/markets/{condition_id}
CLI
vike-data pm market
MCP
polymarket_market_detail
Cost
1 request
Free APIArchiveStreamMCP

Parameters

ParameterInDescription
condition_idrequiredpathThe 0x-prefixed market condition id.
  • A market outside the recorded universe is answered from Polymarket's full market catalog: source says which list answered (recorded or catalog), and a catalog row has tick_size and neg_risk = null. active/closed are derived the same way for both.
  • ⚠ An unknown id is 200 [], never a 404. ⚠ A TOKEN id in this position returns [] too: the route cannot look up by token (the MCP tool can).

Call it

bash
curl -H "X-API-KEY: $VIKE_API_KEY" \
  "https://data.vike.io/v1/polymarket/markets/0x5db999fad322cea2914535aae5517060c3f80ad6d8c0231cde2124a434d16846"
Polymarket · REST · CLI · MCP

One market's trades, with wallets (paged)

One market's trades newest first, with the wallet behind each: who traded, which side, how much and at what price. History runs from 2026-01-01 to a few minutes ago.

Route
GET /v1/polymarket/markets/{condition_id}/trades
CLI
vike-data pm market-trades
MCP
polymarket_market_trades
Cost
1 request
Free APIArchiveStreamMCP

Parameters

ParameterInDescription
condition_idrequiredpathThe 0x-prefixed market condition id (0x and 64 hex digits). An unknown or malformed id is 200 with an empty trades, never a 404.
from_msqueryTrade time, epoch ms, inclusive. Default: from the first trade.
to_msqueryTrade time, epoch ms, exclusive. Must be greater than from_ms. Default: no upper bound.
cursorqueryResume strictly after the last row of a previous page: pass its next_cursor back unchanged.
limitqueryRows per page. Default 1000, hard cap 10000. A page of 1,000 typically takes 0.5 to 2 seconds and a full 10,000 up to about 10 seconds when the service is busy; each page counts as one request, so ask for full pages.
  • Envelope {trades, has_more, next_cursor}; next_cursor is a string only while has_more is true and null otherwise. Walk a market's whole history by following next_cursor; bound it with from_ms / to_ms, a half-open [from_ms, to_ms) window. Rows are ordered by time and then by a fixed tie-break, so a page boundary inside one block neither repeats nor skips a row.
  • Each row: ts (epoch ms, the block's time, whole seconds), tx_hash, log_index, block_number, proxy_wallet, name and pseudonym (Polymarket's display labels, empty when unset), side (BUY or SELL), role (maker or taker), outcome, outcome_index, token_id, size (shares) and price (0 to 1).
  • ⚠ proxy_wallet is the Polymarket proxy wallet that placed the order, not necessarily the person's own address. ⚠ side is per token: a buy of one outcome and a sell of the other can be the same bet.
  • ⚠ One row is one ORDER's fill, not one match. A match is several rows: the resting maker orders that were hit, and one taker row for the aggressor, whose size is the sum of theirs. Adding size * price over both roles counts the match twice, and the two roles price a complementary-token match differently (over 15 minutes of one market: $11,060 summed over maker rows, $17,066 over taker rows). Pick one role and stay with it; never add both.
  • ⚠ A few percent of fills are not rows. Fills one wallet made on one token inside a single transaction can be merged into one row, so a count here can sit under the on-chain fill count (-3.2% of fills and -2.3% of USD over 58 markets checked on 2026-10-17).

Call it

bash
curl -H "X-API-KEY: $VIKE_API_KEY" \
  "https://data.vike.io/v1/polymarket/markets/0x5db999fad322cea2914535aae5517060c3f80ad6d8c0231cde2124a434d16846/trades?limit=50"
Polymarket · REST · CLI · MCP

On-chain settlement

The ON-CHAIN resolution row for one market, as an array of 0 or 1 rows.

Route
GET /v1/polymarket/settlements/{condition_id}
CLI
vike-data pm settlement
MCP
polymarket_settlement
Cost
1 request
Free APIArchiveStreamMCP

Parameters

ParameterInDescription
condition_idrequiredpathThe 0x-prefixed market condition id. As with /markets/{condition_id}, a token_id here returns [].
  • ⚠ [] means "the chain resolved nothing", NOT "open". ~2,134 markets are closed by Polymarket with no on-chain resolution (cancellations, UMA voids), so an empty settlement is not "still trading" — which is why active/closed on /markets read BOTH sources rather than this one alone.
  • market_known is false for a resolved market with no market-list row: its slug, token_ids, outcomes, question, winning_token_id and winning_outcome are then empty, while the on-chain fields are still exact.

Call it

bash
curl -H "X-API-KEY: $VIKE_API_KEY" \
  "https://data.vike.io/v1/polymarket/settlements/0x5db999fad322cea2914535aae5517060c3f80ad6d8c0231cde2124a434d16846"
Polymarket · REST · CLI · MCP

On-chain settlements (paged)

On-chain settlements, oldest resolution first, ordered (resolved_ts_ms, condition_id).

Route
GET /v1/polymarket/settlements/bulk
CLI
vike-data pm settlements
MCP
polymarket_settlements_bulk
Cost
1 request
Free APIArchiveStreamMCP

Parameters

ParameterInDescription
from_msqueryResolution time, epoch ms, inclusive. Default: from the first resolution.
to_msqueryResolution time, epoch ms, exclusive. Must be greater than from_ms. Default: no upper bound.
slug_prefixqueryOnly markets whose slug starts with this, e.g. btc-updown-5m-. Lowercase letters, digits and -, up to 100 characters; anything else is a 400. A market with no known slug never matches.
cursorqueryResume strictly after this resolved_ts_ms:condition_id, taken from a previous page's next_cursor.
limitqueryRows per page. Default and hard cap 5000. A full page typically takes 1 to 3 seconds and each page counts as one request, so ask for full pages.
  • Envelope {settlements, has_more, next_cursor}; next_cursor is a string only while has_more is true and null otherwise. Each row is exactly what /settlements/{condition_id} returns for that market. Walk every settled 5-minute BTC market with ?slug_prefix=btc-updown-5m-&limit=5000 and follow next_cursor: 5,000 markets per request instead of one.
  • Pages are rebuilt every 5 minutes: a market that has just resolved on-chain can take up to about 5 minutes to appear here, and a row with market_known false gets its market fields at the first rebuild after the market is added. /settlements/{condition_id} is always current.

Call it

bash
curl -H "X-API-KEY: $VIKE_API_KEY" \
  "https://data.vike.io/v1/polymarket/settlements/bulk?slug_prefix=btc-updown-5m-&limit=100"
Endpoints

Order book, stats and candles

One token’s book at any moment since 2026-07-25, its tape summary and its candles.

Polymarket · REST · CLI · MCP

Order-book snapshot

The nearest book snapshot at or before ts, flattened to levels.

Route
GET /v1/polymarket/orderbook
CLI
vike-data pm orderbook
MCP
polymarket_orderbook
Cost
1 request
Free APIArchiveStreamMCP

Parameters

ParameterInDescription
token_idrequiredqueryThe outcome token.
tsqueryAs-of epoch ms. The nearest snapshot at-or-before it is used; omit for the latest.
depthqueryLevels per side. Default 25, hard cap 25.
  • as_of_ts repeats on every row and is the snapshot ACTUALLY used, not the ts requested. Asks precede bids (side sorts alphabetically), each ascending by level, in one array.
  • ⚠ A book can be one-sided, so depth=5 returning five rows rather than ten is correct. ⚠ And this endpoint can currently return every level SEVERAL TIMES.

Call it

bash
curl -H "X-API-KEY: $VIKE_API_KEY" \
  "https://data.vike.io/v1/polymarket/orderbook?token_id=1910830010387565971650098373488592514702818137344973088263643820608151819241&depth=10"
Polymarket · REST · CLI · MCP

One token's tape summary

Event counts, trade volume and first/last timestamps for one token.

Route
GET /v1/polymarket/market_stats
CLI
vike-data pm market-stats
MCP
polymarket_market_stats
Cost
1 request
Free APIArchiveStreamMCP

Parameters

ParameterInDescription
token_idrequiredqueryThe outcome token. Omitting it returns 400 {"error":"market_stats requires token_id"}.
  • ⚠ ALWAYS exactly one row. An unknown token returns one row of ZEROS, not [].

Call it

bash
curl -H "X-API-KEY: $VIKE_API_KEY" \
  "https://data.vike.io/v1/polymarket/market_stats?token_id=1910830010387565971650098373488592514702818137344973088263643820608151819241"
Polymarket · REST · CLI · MCP

Polymarket candles

Bars at a fixed interval, OLDEST first. With to and no from, limit keeps the newest bars up to to; the rows still come back oldest first.

Route
GET /v1/polymarket/ohlcv
CLI
vike-data candles polymarket
MCP
polymarket_ohlcv
Cost
1 request
Free APIArchiveStreamMCP

Parameters

ParameterInDescription
token_idrequiredqueryThe outcome token.
intervalrequiredqueryOne of 1m, 5m, 1h, 1d. Anything else returns 400 naming the four accepted values.
fromqueryEpoch MILLISECONDS, INCLUSIVE lower bound.
toqueryEpoch MILLISECONDS, INCLUSIVE upper bound.
limitqueryMax bars. Default 500, hard cap 1000. With to and no from, the limit bars nearest to (so to=X&limit=1 is the last bar at or before X); otherwise the oldest bars of the window.
  • ⚠ from/to here are epoch-ms INTEGERS and to is INCLUSIVE — unlike /v1/polymarket/events, whose window is half-open, and unlike /v1/polymarket/archive/datasets, where the same two names are YYYY-MM-DD STRINGS. A date-shaped value here does not parse as an integer and is therefore IGNORED, answering the request unfiltered.
  • ⚠ The two required args are checked in order — token_id first, then interval — so ?interval=1h alone reports the missing token, not the other way round.

Call it

bash
curl -H "X-API-KEY: $VIKE_API_KEY" \
  "https://data.vike.io/v1/polymarket/ohlcv?token_id=1910830010387565971650098373488592514702818137344973088263643820608151819241&interval=1h&limit=48"
Endpoints

Event tape

Every recorded book snapshot, price change and trade, in order.

Polymarket · REST · CLI · MCP

Raw event tape (paged)

The raw per-market event tape, ordered (local_ts, seq, token_id).

Route
GET /v1/polymarket/events
CLI
vike-data pm tape
MCP
polymarket_tape
Cost
1 request
Free APIArchiveStreamMCP

Parameters

ParameterInDescription
token_idqueryA single token — sugar for a one-element token_ids.
token_idsqueryComma-separated token ids, max 100 per request. Wins over token_id if both are given.
from_msrequiredqueryWindow start, epoch ms, inclusive.
to_msrequiredqueryWindow end, epoch ms, exclusive. Must be greater than from_ms.
event_typequeryFilter to one of book, price_change, trade, tick_size_change, status.
cursorqueryResume from a previous page's next_cursor, passed back unchanged. It is local_ts:seq:token_id, with a ~n suffix when the page ended between two rows that share one local_ts:seq:token_id (two prints of a token in the same millisecond); no row is skipped or repeated.
limitqueryMax rows per page. Default 5000, hard cap 50000.
  • ⚠ One of two routes whose body is an envelope (the other is /settlements/bulk): {events, has_more, next_cursor}. bids/asks are strings carrying embedded JSON, and is_snapshot is a number, 0 or 1.
  • Bounded in every dimension on purpose: both window bounds required, the window itself capped at 24h, token_ids capped at 100, limit capped at 50,000. next_cursor is a string only while has_more is true and null otherwise.

Call it

bash
curl -H "X-API-KEY: $VIKE_API_KEY" \
  "https://data.vike.io/v1/polymarket/events?token_id=1910830010387565971650098373488592514702818137344973088263643820608151819241&from_ms=1793688535000&to_ms=1793689435000&event_type=trade"
Endpoints

Traders

Wallet profiles, smart money and the leaderboard, read from the on-chain trade tape.

Polymarket · REST · CLI · MCP

One trader's profile

A Polymarket wallet's profile: lifetime volume and trade counts, realized P&L and hit rate over window (by RESOLUTION time), markets, recent trades, open positions and an equity curve. A wallet with no recorded trades answers 400 {"error": ...}, not zeros.

Route
GET /v1/polymarket/wallets/{address}
CLI
vike-data pm wallet
MCP
polymarket_wallet
Cost
1 request
Free APIArchiveStreamMCP

Parameters

ParameterInDescription
addressrequiredpathThe wallet's 0x-prefixed proxy-wallet address (40 hex digits). Anything else is a 400.
windowquery24h, 7d, 30d or all. Default all. Any other value is a 400. See *What the window moves* for which fields it changes.
  • The headline realized_pnl_usd, resolved_markets and hit_rate count only markets already settled in Polymarket's own daily resolution records, so a market that settled on chain in the last day can show realized_pnl in markets[] (which also reads the on-chain settlement) before the headline counts it. The headline hit_rate is volume-weighted; category_breakdown[].hit_rate is a plain count (wins / resolved), and category_breakdown[].hit_rate_volume_weighted is the headline's definition per category. Each open_positions row carries its token_id.
  • The wallets that trade the same markets (correlated) are not in this response: that scan is far heavier than the rest of the profile, so it is its own endpoint, GET /v1/polymarket/wallets/{address}/correlated. The key is absent, not an empty list, and every successful response says so in an X-Vike-Hint header.

Call it

bash
curl -H "X-API-KEY: $VIKE_API_KEY" \
  "https://data.vike.io/v1/polymarket/wallets/0xa8f47125d4fe93f9079fdf999f950d71e4ec2ff2?window=30d"
Polymarket · REST

Wallets that trade the same markets

The other wallets that trade the same markets as address, as a BARE ARRAY of up to 8 rows: most shared markets first, then the largest overlap volume. Each row has proxy_wallet, pseudonym, display_name, shared_markets, overlap_volume_usd, overlap_trades and last_seen.

Route
GET /v1/polymarket/wallets/{address}/correlated
CLI
—
MCP
—
Cost
1 request
Free APIArchiveStreamMCP

Parameters

ParameterInDescription
addressrequiredpathThe wallet's 0x-prefixed proxy-wallet address (40 hex digits). Anything else is a 400.
  • A wallet is listed when it shares at least 3 markets and at least $500 of volume with address. Only the address's 1,000 largest markets by its own volume are compared, so a market-making bot is matched on its biggest markets, not all of them. An answer is cached for up to 3 minutes.
  • This block used to be the correlated key of GET /v1/polymarket/wallets/{address}, which no longer carries it: the scan is the heaviest read of the profile, so a client that does not want it never waits for it. [] means no wallet qualifies, and is also the answer for an address with no recorded trades (the profile answers that with a 400). The MCP and AI-chat tool polymarket_wallet still returns the block inline.

Call it

bash
curl -H "X-API-KEY: $VIKE_API_KEY" \
  "https://data.vike.io/v1/polymarket/wallets/0xa8f47125d4fe93f9079fdf999f950d71e4ec2ff2/correlated"
Polymarket · REST · CLI · MCP

Smart-money signals

flows: markets with the largest net inflow from the smart-money cohort over the window. mispricings: markets where that cohort bought meaningfully below the current mid. The cohort is wallets with $1k+ realized PnL over 5+ resolved markets and $5k+ volume. A flows row's buy_inflow, sell_outflow and net_inflow add both outcomes, so buying Up and buying Down both read as inflow; outcomes splits them per outcome, and a market's direction is the difference between its outcomes' net_inflow.

Route
GET /v1/polymarket/smart_money
CLI
vike-data pm smart-money
MCP
polymarket_smart_money
Cost
1 request
Free APIArchiveStreamMCP

Parameters

ParameterInDescription
modequeryflows (default) — markets with the largest net cohort inflow in the window. mispricings — markets where the cohort bought meaningfully below the current mid. Any other value is a 400.
hoursqueryLookback window in hours, an integer from 1 to 720. Default 24. Anything else is a 400.
categoryqueryRestrict to one market category (at most 64 characters). Default: all. An unknown category returns [], not an error.
limitqueryMaximum rows, a positive integer. Default 10; values above 20 are capped at 20.

Call it

bash
curl -H "X-API-KEY: $VIKE_API_KEY" \
  "https://data.vike.io/v1/polymarket/smart_money?mode=flows&hours=24&limit=10"
Polymarket · REST · CLI · MCP

Wallet leaderboard

The wallet leaderboard: Polymarket wallets ranked by realized P&L, hit rate, volume or trade count, as an ARRAY of rows (an empty array means no wallet passes the filters). The same board vike.io/polymarket shows, read from the hourly leaderboard table, not the tape.

Route
GET /v1/polymarket/leaderboard
CLI
vike-data pm leaderboard
MCP
polymarket_leaderboard
Cost
1 request
Free APIArchiveStreamMCP

Parameters

ParameterInDescription
categoryqueryall (default), Crypto, Sports, Politics, Pop-Culture or Tech. Every figure is recomputed on that category's markets only. Any other value is a 400.
windowquery24h, 7d, 30d or all. Default all. The period behind trades_window, volume_window_usd and realized_pnl_window_usd (P&L of the markets that RESOLVED inside it), and what the *_window sorts rank on; with no sort, 24h / 7d / 30d rank on realized_pnl_window_usd. 24h, 7d and 30d are rebuilt hourly and a market's resolution time can be corrected later, so they can be revised; all is not affected. Any other value is a 400.
sortqueryDefault realized_pnl_window when window is 24h, 7d or 30d, realized_pnl when it is all. realized_pnl (lifetime USD, largest first, whatever the window), realized_pnl_asc (biggest losers first), realized_pnl_window and realized_pnl_window_asc (P&L inside window), hit_rate (highest first, nulls last; the top is often wallets that buy near-certain outcomes just under $1, a 100% rate on a sliver of P&L, so set realized_pnl_usd against volume_all_usd before reading it as skill), resolved (most resolved markets), volume_24h and trades_24h (USD volume and trade count inside window; the names are historical), volume_all, trades_all, markets (lifetime), last_seen (most recent first). Ties break on the wallet address; hit_rate ties break on the most resolved markets first, then the largest lifetime volume, then the address. Any other value is a 400.
min_resolvedqueryMinimum resolved markets, a count from 0 to 4294967295. Default 20, so a hit_rate rests on a real sample; 0 includes wallets too thin for one.
min_volume_usdqueryMinimum lifetime volume in USD (buys plus sells), a finite number of 0 or more. Default 0.
min_avg_usdqueryMinimum average trade size in USD, a finite number of 0 or more. Default 0. 20 leaves out every wallet tagged bot.
limitqueryRows per page, a positive integer. Default 20; values above 50 are capped at 50.
offsetqueryRows to skip, an integer from 0 to 1000. Default 0. The board is rebuilt hourly, so a page fetched after a rebuild can repeat or skip a wallet. Above 1000 is a 400: narrow with category or a min_* filter instead.
  • hit_rate is a FRACTION (0.62 = 62%), volume-weighted, and null where undefined, never 0; hit_rate_ci is the +/- half-width of its 95% Wilson interval, also a fraction. tags are whale, bot, hot and cold. first_seen is the first trade in the recorded tape (it starts 2026-01-01), so it does not show a wallet is new.

Call it

bash
curl -H "X-API-KEY: $VIKE_API_KEY" \
  "https://data.vike.io/v1/polymarket/leaderboard?window=30d&sort=realized_pnl&limit=20"
Endpoints

Archive files

The daily Parquet files: list them, and resolve one to a download.

Polymarket · REST · CLI · MCP

Archive file index

Every known archive Parquet file, filtered and paged, in MANIFEST ORDER.

Route
GET /v1/polymarket/archive/datasets
CLI
vike-data pm archive
MCP
polymarket_archive
Cost
1 request
Free APIArchiveStreamMCP

Parameters

ParameterInDescription
assetqueryMatches family-layout rows only, e.g. btc. Supplying it excludes every flat row.
tenorqueryMatches family-layout rows only, e.g. 5m.
streamqueryOne of book_events, trades, l1_quotes.
fromqueryYYYY-MM-DD, inclusive lower date bound.
toqueryYYYY-MM-DD, inclusive upper date bound.
limitqueryMax rows. Default 200, hard cap 1000.
offsetquerySkip this many matching rows. Default 0.
  • {"datasets": [...], "limit": n, "offset": n, "total": n} — total is the filtered count BEFORE paging, and limit/offset echo the EFFECTIVE values.
  • ⚠ TWO row shapes on one endpoint. A family row carries asset and tenor; a flat row OMITS both keys entirely rather than emitting null. Supplying either filter therefore excludes every flat row by construction.
  • ⚠ from/to are DATE STRINGS here and epoch-ms integers on /v1/polymarket/ohlcv. Same names, different endpoints, different types.

Call it

bash
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"
Polymarket · REST · CLI · MCP

Resolve one archive file

Resolve exactly ONE dataset to a temporary download link.

Route
GET /v1/polymarket/archive/url
CLI
vike-data pm archive
MCP
polymarket_archive
Cost
1 request
Free APIArchiveStreamMCP

Parameters

ParameterInDescription
daterequiredqueryYYYY-MM-DD. Omitting it returns 400 {"error":"archive/url requires date"}.
streamrequiredqueryOne of book_events, trades, l1_quotes.
assetquerySupply both asset and tenor to resolve the family layout, or neither to resolve the flat layout.
tenorqueryWith asset, selects the family layout.
redirectquerytrue (or 1) returns 302 with the file in Location; the JSON body is still sent, so a client that does not follow redirects keeps the answer.
  • Returns a single dataset OBJECT — not an array, not an envelope. The only route in this family with that shape, the only one that can answer 302, and the only one that sets a header.
  • url is a presigned link to that one file, valid for expires_in seconds (7 days) until expires_at; it needs no API key, so do not share it. A file your account may not download is a 403.
  • ⚠ ?redirect=1 returns 302 with a Location header AND the full JSON body, so a client that does not follow redirects still gets the answer.
  • ⚠ "No such dataset" is a 400, not a 404: the manifest was read and the combination simply has no file. A 404 would claim the route does not exist.
  • ⚠ Both asset and tenor, or neither. Exactly one is rejected as ambiguous rather than guessed at.

Call it

bash
curl -H "X-API-KEY: $VIKE_API_KEY" \
  "https://data.vike.io/v1/polymarket/archive/url?date=2026-11-02&stream=trades"
Endpoints

Live stream catch-up

What the WebSocket sent while you were disconnected, from a cursor, with the same filters.

Polymarket · REST · MCP

Stream catch-up

Stored events of one live-stream channel after a cursor, oldest first: the REST catch-up of wss://stream.vike.io/v1/stream/polymarket, for what a client missed while it was disconnected (events are kept 3 days). Pass the channel's filters as query parameters, as on the socket: a list as a comma list (wallet=0x..,0x..), a number as a number (min_usd=1000); an unknown filter, or one the channel does not take, is a 400 naming it.

Route
GET /v1/polymarket/stream-events
CLI
—
MCP
stream_events
Cost
1 request
Free APIArchiveStreamMCP

Parameters

ParameterInDescription
channelrequiredquerypm.new_markets, pm.positions, pm.price_moves, pm.resolutions, pm.trades
cursorquerynext_cursor of the previous page or the cursor of a stream frame. Empty: the oldest retained event
limitqueryDefault 200, clamped to 1-1000
  • Channels and their filters:
  • - pm.new_markets: class - pm.positions: action, market, min_usd, wallet - pm.price_moves: market, min_move, move, token_id - pm.resolutions: market - pm.trades: market, min_usd, pnl_tier, role, side, volume_tier, wallet
  • Returns {events: [{cursor, event}], next_cursor, has_more}. event is exactly what the socket sent, so dedupe on event.event_id. Pass next_cursor back as cursor while has_more is true. A window in which the channel was idle (nobody subscribed) comes as an item {cursor, gap} in its place. A cursor older than the retention is a 410 naming the oldest cursor accepted; omit cursor to start at the oldest stored event.

Call it

bash
curl -H "X-API-KEY: $VIKE_API_KEY" \
  "https://data.vike.io/v1/polymarket/stream-events?channel=pm.trades&limit=50"
Response fields

What comes back, field by field

The datasets behind these routes, with real rows and loading code.

Polymarket · API dataset · search · settle

Markets & settlements

Market search, one-market detail, and the on-chain resolution per condition.

Route
GET /v1/polymarket/markets
Cadence
Kept by the market recorder; state derived per request
Coverage
Recorded markets with derived state: closed when the chain resolved the condition OR Polymarket's own feed closed it. /markets filters by slug substring and active | closed (never both), newest end_date first, limit up to 100. `/markets/{condition_id}` answers a market outside the recorded set from Polymarket's full market catalog; its `source` says which list answered. `/settlements/{condition_id}` is the on-chain resolution — [] means the chain resolved nothing, not that the market is open; `/settlements/bulk` pages every settlement oldest resolution first (filter by resolution time and slug prefix, up to 5,000 a page, next_cursor + has_more) from pages rebuilt every 5 minutes, so a newly resolved market can appear there up to about 5 minutes after `/settlements/{condition_id}` shows it. Candles per token: /ohlcv.
Rows
Free APIArchiveStreamMCP

Fields

FieldTypeDescription
condition_idstringThe market, 0x-prefixed
slugstringURL slug
activeinteger1 when not closed, else 0
closedinteger1 when resolved on chain or closed by the venue
end_dateintegerScheduled end, epoch milliseconds
neg_riskinteger|null1 for a neg-risk market; null on a catalog row
tick_sizenumber|nullPrice increment; null on a catalog row
token_idsarrayOne outcome token id per outcome

Real rows

Markets & settlements · rows

GET
Open this side to see the captured response.

    

Load it

bash
curl -H "X-API-KEY: $VIKE_API_KEY" \
  "https://data.vike.io/v1/polymarket/markets?active=true&limit=25"

Every parameter of /v1/polymarket/markets → · back to the catalog

Data model

Ids, coverage and the traps in the answers

Recorded and catalog markets. /markets lists the markets Vike records. /markets/{condition_id} also answers from Polymarket’s full catalog; every row says which in source: recorded or catalog.
Coverage starts 2026-07-25. The recorded book, the tape, candles and the archive start that day; a window that ends earlier answers empty, with the reason in X-Vike-Note.
Settlement is chain truth. [] from /settlements/{condition_id} means the chain resolved nothing, never “still open”: Polymarket closes some markets with no on-chain resolution.
Event rows: parse twice. bids and asks are JSON text, not arrays; a 0 in a field the event type does not fill means “not set”, not a price.
Order book: de-duplicate. The same (side, level) can arrive several times; read a side’s depth as its max(level). A book can be one-sided.
Smart money = wallets with at least $1,000 of realized P&L, 5 or more resolved markets and $5,000 of volume.
Errors

Status codes

Branch on the status code, not the body.

StatusMeaningBody
400The input was rejected: an unknown market or dex, a malformed identifier, a cursor from another query. Polymarket routes also refuse unknown query parameters.Hyperliquid / on-chain {"detail": "…"} · Polymarket {"error": "…"}
401Missing, invalid or deactivated credential — on /v1 and the archive alike.Turned away before the API runs, so the body can be an HTML page. Do not assume JSON.
404No such route or archive file. An unknown condition_id on a Polymarket detail route is 200 [], not a 404.{"detail": "Not Found"}
422A parameter failed validation: wrong type, or outside the bounds the route declares.{"detail": [ … ]}
429Hourly limit exceeded, or on /v1 the per-minute cap (200 a minute per key).Retry-After: 60 (hourly) or Retry-After: 1 (per-minute) header, JSON error body
503The data store failed. Not your request — retry with back-off.Hyperliquid / on-chain {"detail": "upstream unavailable"} · Polymarket {"error": "upstream unavailable"}
  • A failed query is never a 200 with an empty body. An empty list means there were no rows.
  • The /v1/onchain routes and Hyperliquid /traders and /positions/match run through a shared tool layer, which reports its own failures in-band — so an internal error there can arrive as a 400 carrying the error text.
  • MCP answers a bad credential with HTTP 401, a WWW-Authenticate: Bearer resource_metadata=... header (where an OAuth client starts discovery) and a JSON-RPC error (-32000, Invalid or missing API key). A rate-limit trip there is a real 429. Check the body, not just the status.