Skip to content

Rate limits

Requests are rate-limited per API key, with separate limits for different endpoint classes — minting verification sessions is metered independently from general reads and writes, so a burst of one doesn’t consume the other’s headroom. Test and live keys are limited independently.

Specific limit numbers are not published here — they can be tuned per account, so a hard-coded number would go stale. Your current limits are visible in the portal under Developers → Usage. Read them there, and treat the response headers below as the live source of truth at request time.

When you exceed a limit, the API responds with:

  • HTTP 429 and error code: rate_limit_exceeded (see Errors);
  • a Retry-After header — how many seconds to wait before retrying;
  • X-RateLimit-Limit and X-RateLimit-Remaining — the ceiling for that endpoint class and how many requests you have left in the current window.

X-RateLimit-Limit and X-RateLimit-Remaining are returned on every response, not just 429s, so you can see yourself approaching a limit and slow down before you hit it.

On a 429, wait for Retry-After and retry. For repeated failures, back off with jittered exponential retry so a fleet of clients doesn’t retry in lockstep and stampede the moment the window opens:

async function requestWithRetry(url, init, { maxRetries = 5 } = {}) {
for (let attempt = 0; ; attempt++) {
const res = await fetch(url, init);
if (res.status !== 429 || attempt >= maxRetries) return res;
const retryAfter = Number(res.headers.get('Retry-After')) || 2 ** attempt;
const jitter = Math.random() * 0.3 * retryAfter; // up to +30%
await new Promise((r) => setTimeout(r, (retryAfter + jitter) * 1000));
}
}
  • Errors — the rate_limit_exceeded envelope.
  • Pagination — page with limit=100 to make fewer requests.
  • Webhooks — push, so you don’t poll (and rate-limit) for status changes.