Rate limits
One hourly counter per API key, shared by MCP and the REST API — plus the one surface that is authenticated on every request and charged on none.
Every MCP tool call and every REST API call spends one unit of the same hourly budget. Archive downloads are authenticated on every request and recorded on every request, and charged on none. There is one number, one counter, and one exclusion.
The number
20,000 requests per rolling hour. One value applies to every credential — there are no plan tiers, no per-endpoint ceilings and nothing to configure.
Older numbers you may have seen are wrong
This limit was raised on 2026-07-29. Documentation and product pages previously stated 100 calls/hour for MCP and 2,000/hour for the REST API; both are stale by an order of magnitude or more.
Separately, archive downloads stopped spending this budget on 2026-09-02. Any page telling you that a Parquet download costs you requests, or that an hour of archive downloads leaves nothing for your MCP client, predates that change.
The window slides. What counts is your usage over the previous hour, measured from now, so capacity returns continuously as old requests age out — there is no fixed reset at the top of the hour, and waiting for one will not help you. A request is counted before it is compared against the ceiling, so 20,000 is the number of requests admitted per window, inclusive.
One counter, three surfaces
Every authenticated request is recorded against your credential under a label you can see in your usage view. Two of the three surfaces also spend budget:
| You call | Recorded as | Spends the hourly budget |
|---|---|---|
https://vike.io/mcp | mcp | yes |
https://data.vike.io/v1/... | api_<namespace>_<resource> | yes |
https://data.vike.io/archive/... | archive_download | no |
The two metered surfaces do not have budgets of their own — they share the single counter. An
hour of /v1 calls leaves nothing for your MCP client: between those two, the labels separate your
usage analytics, not your budget. The archive is the one surface separated in both.
Per key, not per account
The counter is keyed on the credential, not on its owner, so each of your API keys gets its own 20,000. Issuing a second key is a legitimate way to isolate a bulk job from an interactive one, and one key tripping the limit does not affect another.
OAuth is the exception. Every OAuth token you own shares one pooled counter, held per user rather than per token. Two connected Claude Desktop clients draw from the same budget; two API keys do not.
The archive is authenticated but not metered against your hour
Every request to https://data.vike.io/archive/... still validates its credential, and still
appears in the usage view on your account page. It simply never reaches the rate check. No archive
request can consume your hourly budget, and no amount of downloading can rate-limit you.
Why a request is the wrong unit for a bulk file
The gate in front of the archive counts HTTP requests. It does not see files, or bytes, or downloads — and a Range request is a separate HTTP request.
A remote Parquet read fetches the footer, then each column chunk of each row group it needs, as its
own Range request. The archive actively invites this: manifest.json advertises
"range_requests": true (verified in the live manifest), and the server returns Accept-Ranges,
so pyarrow, DuckDB, fsspec and every other reader will use ranges by default.
The measurement that removed the charge
Measured on the live archive: one 1.26 GB partition produced 20,237 separate requests — more than the entire hourly ceiling, for a single file. Almost every rate-limit rejection recorded in the platform's whole history was an archive download, and every one of them was a customer using the format exactly as intended.
The meter was counting the reader's access pattern rather than the download, so the archive stopped spending the budget. The real cost of a bulk transfer is bandwidth, which is bounded separately at 50 MB/s per connection.
Download whole files anyway
Remote-reading no longer burns your hour — it still costs you time
Pointing pandas, DuckDB or fsspec straight at an archive URL re-fetches the file's footer and column chunks across the network on every query, at a rate capped per connection. Pull the partition once instead.
One file is one request. Fetch it, then point your reader at the local copy:
curl -O -H "X-API-Key: $VIKE_API_KEY" \
"https://data.vike.io/archive/venue=polymarket/date=2026-09-01/trades.parquet"An interrupted transfer resumes with -C - rather than starting over:
curl -C - -O -H "X-API-Key: $VIKE_API_KEY" \
"https://data.vike.io/archive/venue=polymarket/date=2026-09-01/book_events.parquet"Row-group pushdown and column pruning still work against the local file; they just work against your disk instead of across a 50 MB/s link.
Download less, not more cleverly
Full-day book_events partitions run 4–7 GiB. If you need one market family rather than the whole
Polymarket universe, the archive publishes a second, additive layout that groups the crypto up/down
families into much smaller files:
/archive/venue=polymarket/asset=btc/tenor=5m/date=2026-09-01/book_events.parquetSame schema as the date= layout. manifest.json lists every (asset, tenor, date) triple with
its row count and byte size, so you can pick exactly the files you need before transferring a byte
— and the manifest itself needs no key at all, like the free samples under /archive/samples/.
The counter is a backstop, not a meter
The limit is enforced approximately, and deliberately favours availability over exactness:
- It is enforced per server process. Requests from one client can be handled by different processes, each keeping its own view of your count, so a client whose requests spread across them can see an effective ceiling meaningfully above the nominal one before every process agrees it is over.
- It refreshes on a short interval. Between refreshes the count is tracked locally with no round trip, so a burst can briefly overshoot before the next refresh catches up.
- A backend failure does not open the gate. If a refresh fails or times out, the last known count is reused rather than the check being skipped.
Treat 20,000 as the number you must design under, not a number you can calibrate against. Do not build a client that runs deliberately at the edge of it.
When you are limited
You get HTTP 429 with a Retry-After: 60 header on every metered surface. Every layer that can
return one quotes the same 60, deliberately, so two hops cannot disagree — and it is advisory: a
sliding hourly window has no single correct answer to "when will capacity exist", so 60 seconds is a
sane back-off hint rather than a promise.
The archive cannot return a rate-limit 429 at all, because an /archive/ request is never metered.
A missing or invalid credential there is still a 401.
Honour the header, back off, and retry. A rate-limited request is itself recorded and itself counts, so hammering a closed door keeps the door closed. The exact body shapes, and the one surface where a rate-limit trip and an auth failure carry different HTTP statuses, are on Errors.
Watching your usage
Recent calls, per key, are visible under Account → API Keys at vike.io/account?tab=api-keys. Archive downloads appear here like everything else — they are recorded, just not charged. Each call also carries a credit value (0–4 for an MCP tool) recorded for accounting, but the hourly limit counts requests, not credits — a 0-credit call consumes a unit of the hourly budget exactly like any other. What each endpoint and tool costs is on Limits and credits.