Every operation on the platform is rate limited, with limits sized to each operation's sensitivity. Well-behaved clients never notice them.
Exceeding a limit returns 429 with the standard error envelope and a Retry-After header with the number of seconds to wait. There are no X-RateLimit-* headers today; the honest contract is: on 429, wait Retry-After seconds.
{
"error": {
"code": "RATE_LIMITED",
"message": "Too many requests. Try again shortly.",
"requestId": "req_8c1d44e2a9f0"
}
}If the limiter itself is unavailable, sensitive operations fail closed with 503 RATE_LIMITER_UNAVAILABLE and a Retry-After. Treat it exactly like a 429 with a short wait.
async function withBackoff<T>(run: () => Promise<Response>): Promise<Response> {
for (let attempt = 0; ; attempt++) {
const res = await run();
if (res.status !== 429 && res.status !== 503) return res;
if (attempt >= 4) return res;
const retryAfter = Number(res.headers.get("Retry-After") ?? 0);
const backoff = Math.min(30_000, 500 * 2 ** attempt);
const jitter = Math.random() * 250;
await new Promise((r) => setTimeout(r, Math.max(retryAfter * 1000, backoff) + jitter));
}
}Retry-After when present, and add jitter so concurrent clients do not retry in lockstep.