Rate limits
Each API key can make 100 requests a minute, and all the keys of a business together 300. That’s plenty for a busy till, and stops a runaway loop doing damage.
How the limit works
There are two buckets, and a request needs a token from both. Each key has a bucket of 100 requests that refills steadily, at 100 a minute. Your business has a second bucket of 300 requests, at 300 a minute, shared by all its keys, so creating more keys doesn’t raise the limit. A short burst can use a whole bucket at once. Every response says how much is left:
RateLimit-Limit: the size of the key’s bucket, 100.RateLimit-Remaining: requests you can make right now, in whichever bucket is lower.
When either bucket is empty, Korti answers 429 rate_limited with a Retry-After header in seconds. The message says which limit you hit. A refused request doesn’t use up any tokens.
A business can have up to 10 active API keys. Revoke one to create another.
HTTP/1.1 429 Too Many Requests
RateLimit-Limit: 100
RateLimit-Remaining: 0
Retry-After: 2
{
"error": {
"type": "rate_limited",
"message": "Too many requests. Each key can make 100 requests a minute. Try again in 2 seconds."
}
}Handle it
Wait the number of seconds in Retry-After, then send the same request again.
async function korti(path: string, init: RequestInit = {}, tries = 3): Promise<Response> {
const res = await fetch(`https://korti.is/v1${path}`, {
...init,
headers: { Authorization: `Bearer ${process.env.KORTI_KEY}`, ...init.headers },
});
if (res.status === 429 && tries > 1) {
const seconds = Number(res.headers.get("Retry-After") ?? 1);
await new Promise((r) => setTimeout(r, seconds * 1000));
return korti(path, init, tries - 1);
}
return res;
}NoteNeed to issue thousands of passes at once, for example when you import a member list? Spread the requests out, or use the CSV import in the dashboard. If you need a higher limit, email korti@korti.is.
Idempotency keys
Every POST and PATCH accepts an Idempotency-Key header of up to 255 characters. Korti remembers the response for 24 hours. Sending the same key and the same request again returns that response, marked Idempotent-Replayed: true, without doing the work twice. The same key with a different request returns 409 idempotency_conflict.
Keys are shared by all live keys of your business, and by all test keys, so a retry that goes out through another key still replays. Server errors aren’t remembered, so retrying after a 500 really tries again. Responses larger than 16 KB are returned but not remembered. Korti keeps at most 2,000 responses per business and forgets the oldest first, so don’t rely on a replay long after the original request.