Skip to content

Rate limits

Every API request is counted against two hourly budgets. Both are enforced, both scale with your plan, and every response tells you where you stand.

Two windows

WindowCountsKeyed on
AccountEvery request from every key you own, combinedThe account owner
Per keyOne key's own requestsThe key

The account window is checked first. It is keyed on the owner rather than the key, so issuing more keys does not buy more requests. The per-key window sits underneath and contains the damage when one key runs away or leaks.

Both are rolling windows, not a counter that empties on the hour. Requests age out gradually as the hour moves.

The MCP server authenticates the same way and draws on the same budgets. A tool call from an AI client and a curl against /query cost the same.

How much you get

Both budgets rise with your plan, and an account with no active paid plan sits on the entry-tier floor.

The exact ceilings are not published, because they are tuned server-side without a release and any number printed here would go stale silently. Your own limit is on every response you make:

X-RateLimit-Limit: 1200

Read it once at startup rather than hard-coding a figure, and your client stays correct through a plan change or a retune.

Reading the headers

Every response carries the window that applies to it:

HeaderMeaning
X-RateLimit-LimitThe hourly ceiling for the reported window
X-RateLimit-RemainingRequests left in it
X-RateLimit-ResetSeconds until the window frees, not a timestamp

Normally these describe the per-key window. On an account-level rejection they describe the account window instead, which is how you tell the two apart without parsing the message.

X-RateLimit-Reset counts seconds forward from now. Add it to the current time rather than reading it as an epoch.

When you hit the limit

The response is 429 with Retry-After in seconds:

HTTP/1.1 429 Too Many Requests
Retry-After: 1800
X-RateLimit-Limit: 600
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1800
{ "code": "rate_limited", "error": "account rate limit exceeded" }

The message names which budget ran out: account rate limit exceeded or api key rate limit exceeded. Wait Retry-After seconds before trying again. Retrying sooner spends the request and gets another 429.

Staying under

  • Watch X-RateLimit-Remaining and slow down as it falls, rather than waiting for the 429. It is on every response, so this costs nothing.
  • Ask for more per request. One breakdown with limit: 100 beats a hundred single-row queries, and counts as one request.
  • Do not poll faster than your data changes. Outside realtime, numbers move on the order of minutes, so a query every few seconds spends budget to receive the same answer.
  • Give each job its own key. The account budget is shared either way, but separate keys keep one runaway job from starving the rest through the per-key window.

Next steps


Ready to take control of your web analytics? Try Statable free for 30 days. No credit card required, full feature access, built for GDPR. Start your free trial or view a live demo.