Skip to content

Rate limits

Limits are enforced per API key, not per client and not per IP. Two keys held by the same integration get their own budgets.

WindowRequests
Per minute100
Per day10,000

These are the defaults attached to a newly issued key. A key can be issued with higher limits — ask, with a number and the reason, and we will set it on the key rather than making you thread a workaround through your code.

Exceeding either window returns:

{
"type": "https://developers.vaki.co/errors/rate_limit_exceeded",
"title": "Too many requests",
"status": 429,
"code": "rate_limit_exceeded",
"detail": "Limit of 100 requests per minute exceeded for this API key.",
"instance": "/v1/checkout_links"
}

The contract is the standard trio, on every response:

HeaderMeaning
RateLimit-LimitRequests allowed in the current window
RateLimit-RemainingRequests left in the current window
RateLimit-ResetSeconds until the window resets

Exponential backoff with jitter, capped, with a maximum number of attempts. The jitter matters: without it, every client you have retries in lockstep and recreates the spike you are backing off from.

async function callVaki(request, attempt = 0) {
const res = await fetch(request);
const retryable = res.status === 429 || res.status >= 500;
if (retryable && attempt < 5) {
const base = Math.min(2 ** attempt * 500, 8000); // 0.5s → 8s, capped
await sleep(base + Math.random() * 500); // jitter
return callVaki(request, attempt + 1);
}
return res;
}

Never retry a 400, 401, 403, 404, 415 or 422 — the answer will not change and you are spending budget to be told the same thing. See Errors.

Most 429s we see are self-inflicted, and all three causes are cheap to fix.

Do not poll on a timer over everything you have ever created. Poll a link when the donor returns from checkout, then a handful of times with backoff, then stop. A link at completed, expired or cancelled is terminal — never poll it again.

Cache what does not change. GET /v1/vakis/{key} for a published cause is effectively static. Cache the need→vaki-key mapping in your own database at creation time rather than resolving it per donation.

Do not fan out. A nightly reconciliation that walks 10,000 donations in parallel will exhaust the daily budget in one burst and starve your live checkout traffic. Walk it serially with a small concurrency limit and only for donations still in a non-terminal state.

A launch video, a media hit or a telethon is a burst, and a 429 during the one hour that matters is the worst possible time for one. Two weeks is plenty of notice; the day before is not.

Mail soporte@vaki.co with:

  • the date and time window, with the timezone spelled out;
  • expected peak donations per minute;
  • your API key’s name (not the key itself, ever).

We raise the limit on your key for the window. There is no self-service control for this yet.