Docs · Reference · Rate limits

Rate limits.

Per-key request budgets on the control-plane REST API — creating agents, listing calls, starting campaigns. Limits are counted per API key in a fixed 60-second window. The default budget is 60 requests per minute per key.

Budgets#

The first request on a key opens a 60-second window; every request in that window counts against the key's budget. When the window expires, the count resets in full — there is no gradual token refill. Exceeding the budget returns 429 until the reset.

The limit is stored per key (rate_limit_rpm), so different keys — say, a high-volume backfill key and a low-volume production key — can carry different budgets. Need more than 60? Ask at support@whizztech.ai.

Rate limits vs. concurrency#

These are two different limits — don't confuse them:

  • Rate limits cap how many API requestsyou make — creating agents, listing calls, starting campaigns, reading usage. That's what this page is about.
  • Concurrency caps how many live calls run at once. That's a separate thing, governed by the concurrent lines included in your plan — not by the request budget here.

In other words: one POST /v1/calls is one request against your rate limit, but the call it starts occupies a concurrent line for its whole duration. A campaign can hold many lines at once while making very few API requests.

Headers#

Every authenticated response reports where you stand:

Rate-limit headers
HTTP/1.1 200 OK
Content-Type: application/json
x-ratelimit-limit: 60
x-ratelimit-remaining: 57
x-ratelimit-reset: 1751795160
FieldTypeDescription
x-ratelimit-limitintegerThe key's budget per 60-second window.
x-ratelimit-remainingintegerRequests left in the current window.
x-ratelimit-resetunix secondsWhen the current window resets and the budget refills.
retry-aftersecondsOnly on 429: how long to wait before retrying (minimum 1).

The 429 body uses the standard error envelope with code rate_limit_exceeded.

Handling 429#

Honor retry-after. It is computed from the actual window reset, so waiting exactly that long always succeeds. A minimal client:

Node — honor retry-after
async function withRetry(fn, maxRetries = 2) {
  for (let attempt = 0; ; attempt++) {
    const res = await fn();
    if (res.status !== 429 || attempt >= maxRetries) return res;
    const retryAfter = Number(res.headers.get("retry-after") ?? 1);
    await new Promise((r) => setTimeout(r, retryAfter * 1000));
  }
}
  • Poll with backoff, not a tight loop. A 1-second poll on 10 in-flight calls is 600 requests/min — 10x the default budget. Grow the interval (say 3s to 15s) to stay well under it.
  • Prefer webhooks for completion. One call.completed delivery replaces an entire polling session — see Webhooks.
  • Watch remaining, not 429s. Every authenticated response carries the headers, so alerting when x-ratelimit-remaining trends toward zero is free and beats reacting after the fact.
  • Split keys by workload. Give bulk backfills their own key so a burst there can never starve production traffic.