vike
PolymarketArchive files (Parquet)

/archive/{partition path}

One path prefix covering the whole archive — two Hive partitionings of the same data behind one path, not two endpoints.

GET https://data.vike.io/archive/venue=polymarket/date={YYYY-MM-DD}/{stream}.parquet
GET https://data.vike.io/archive/venue=polymarket/asset={asset}/tenor={tenor}/date={YYYY-MM-DD}/{stream}.parquet

One path prefix covering the whole archive. The two path shapes above are two Hive partitionings of the same data behind one path, not two endpoints — full detail of both, and which dates each covers, is on Bulk archive.

There is no JSON response to show you. The body is a binary Apache Parquet file — the one that command downloads is 13,459,739 bytes. So the example below asks for the first 2 KB of the next day's partition instead of the whole of it, which is enough to prove the route, the gate and the file type without moving the file:

cURL — probe with a 2 KB range
curl -H "X-API-Key: $VIKE_API_KEY" \
  -r 0-2047 -D - -o /dev/null \
  "https://data.vike.io/archive/venue=polymarket/date=2026-09-02/trades.parquet"

Response headers, verbatim, 2026-09-03:

Response headers
HTTP/1.1 206 Partial Content
Content-Type: application/octet-stream
Content-Length: 2048
Content-Range: bytes 0-2047/12314277
Last-Modified: Thu, 03 Sep 2026 00:32:06 GMT
ETag: "6a98c006-bbe6a5"
Cache-Control: private, no-store
Server: cloudflare
cf-cache-status: DYNAMIC

The first four bytes of that body are 50 41 52 31 — the ASCII PAR1 every Parquet file opens and closes with. The rest is zstd-compressed column data and is not readable as text.

Three of those headers are worth reading as confirmations rather than trivia. 206 with a Content-Range is the Range row of the table below, working — the server served 2,048 bytes of a file it told you is 12,314,277. That total is also the cross-check on manifest.json: its dates entry for 2026-09-02 reports the trades stream at 1,006,555 rows and 12,314,277 bytes — the same total — so a size read from the manifest is the size you will actually be billed bandwidth for. And cf-cache-status: DYNAMIC beside Cache-Control: private, no-store is the third bullet below holding: Cloudflare saw the response and declined to cache it.

Drop the credential and the same URL never reaches the file — the request is refused before the file is opened. The status is 401 Authorization Required and the body is a plain HTML error page from the edge, not a JSON envelope:

Refused without a credential (401)
<html>
<head><title>401 Authorization Required</title></head>
<body>
<center><h1>401 Authorization Required</h1></center>
</body>
</html>

⚠ That 401 body is HTML, not the JSON error envelope the /v1 endpoints return. A client that assumes every failure parses as JSON breaks here — see Errors. It is also indistinguishable from the 401 a path that does not exist returns: probed keylessly on 2026-09-03, the real partition above and an invented date=1999-01-01/nosuchstream.parquet both answered 401 with byte-identical bodies. Without a credential you cannot tell a typo from a refusal, because the gate runs before the lookup.

There are no query parameters. What you can vary is the path and a small set of headers:

cURL — download the partition
curl -H "X-API-Key: $VIKE_API_KEY" \
  -o polymarket-trades-2026-09-01.parquet \
  "https://data.vike.io/archive/venue=polymarket/date=2026-09-01/trades.parquet"
X-API-Keyheaderrequired
The API key. HTTP header names are case-insensitive; the REST spec spells it X-API-KEY and the manifest X-API-Key — same header, same key.
Authorization: Bearer vk_oat_…headerrequired
OAuth 2.1 access token. The bearer is tried first, then the X-API-Key header. Both reach the same account — see Authentication.
Rangeheaderoptional
Supported: responses carry Accept-Ranges: bytes, and the manifest advertises range_requests: true. It is there so an interrupted download can resume, not so a query engine can page a remote file.
venuepathrequired
polymarket. The only venue in the archive today.
datepathrequired
One UTC day, YYYY-MM-DD. Enumerate dates[] in the manifest; do not probe for dates.

| asset | path | family layout only | btc, eth, sol, xrp, doge, bnb, hype, other — read from today's manifest, which is the authority rather than this row. | | tenor | path | family layout only | 5m, 15m, 4h, other, same caveat. | | {stream} | path | yes | book_events, trades or l1_quotes. Schemas differ per stream — Bulk archive. |

¹ One of the two credentials, not both.

A missing file is a legitimate answer in the family layout. A family with zero rows in a stream on a given day has no file for that stream, and the family layout does not cover every date the date= layout does. Enumerate families[] rather than assuming.

Three properties of this location worth knowing before you point a tool at it:

  • Responses carry Cache-Control: private, no-store, on every response. An authenticated file must never be cached at the edge — a cached copy would bypass both the gate and the usage record — so do not expect a CDN to serve a repeat download for you.
  • A directory URL under /archive/ returns a listing rather than a 403, once you present a credential. The listing is HTML.
  • Throughput is capped at 50 MB/s per connection. It is a bandwidth bound, not a request bound; parallel whole-file downloads are the supported way to go faster, and cost one recorded download each.

⚠ This path never returns a rate-limit 429: archive downloads do not draw on the hourly budget at all. A refusal here is a credential problem, not a budget one — see Rate limits and Errors.