Rate limiting
Retry, back off, and smooth out traffic so a 429 never becomes a failed integration.
Rate limits protect platform stability, but an integration that doesn't plan for them will
surface 429s to your users. This page covers the patterns to build in from the start — the
full quota reference lives in API Reference → Rate Limits.
Know which limit you might hit
Four independent ceilings can each return a 429 — check the type field in the error body to
know which one tripped:
team429 typeoptionalapi_key429 typeoptionalip429 typeoptionalendpoint429 typeoptionalRetry with exponential back-off
Always honor Retry-After when present rather than guessing your own delay:
async function withRetry(fn, maxAttempts = 5) {
for (let attempt = 0; ; attempt++) {
try {
return await fn();
} catch (err) {
if (err.code !== 429 || attempt >= maxAttempts - 1) throw err;
const wait = err.retryAfter ?? 2 ** attempt;
await new Promise((r) => setTimeout(r, wait * 1000));
}
}
}Smooth out batch and background jobs
Reconciliation jobs, exports, and any loop over many Transfers or
Beneficiaries are the most common source of 429s, since they issue many
requests in a short window:
- Space out requests instead of firing them concurrently — a fixed delay between calls is simpler and safer than racing against the per-minute ceiling.
- Prefer a small worker pool (5–10 concurrent requests, see
Performance → Concurrent requests) over an
unbounded
Promise.all. - Schedule large batch jobs (settlement exports, reconciliation) outside your peak checkout
traffic hours so they don't compete with the endpoint-level ceiling on
payments.
Don't retry blindly
A 429 is not a transient network error — retrying immediately in a tight loop only makes the
window reset later. Always back off, and stop retrying past a small number of attempts so a
sustained outage surfaces as an alert instead of an infinite retry loop.
Was this page helpful?