vike
API Endpoints

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 callRecorded asSpends the hourly budget
https://vike.io/mcpmcpyes
https://data.vike.io/v1/...api_<namespace>_<resource>yes
https://data.vike.io/archive/...archive_downloadno

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:

Download a file
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:

Resume a download
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.parquet

Same 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.

On this page