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.
Where to find your limits
Section titled “Where to find your limits”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.
The 429 contract
Section titled “The 429 contract”When you exceed a limit, the API responds with:
- HTTP 429 and error
code: rate_limit_exceeded(see Errors); - a
Retry-Afterheader — how many seconds to wait before retrying; X-RateLimit-LimitandX-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.
Backing off
Section titled “Backing off”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)); }}Related
Section titled “Related”- Errors — the
rate_limit_exceededenvelope. - Pagination — page with
limit=100to make fewer requests. - Webhooks — push, so you don’t poll (and rate-limit) for status changes.