Rate limits

Requests are limited per API key. The default is 120 requests per minute; individual deployments may configure a different value. Read the rate-limit headers on every response and back off when you're throttled.

The limit applies to every endpoint, so any call can return 429. Two buckets sit beside the per-key one:

BucketDefaultKeyed by
Requests without a recognisable key — an unauthenticated GET /v1/ping, or a bad bearer token30 per minuteIP address
Creating and updating webhook endpoints10 per minuteAPI key

The per-key bucket belongs to the key's id, not its secret: a rolled replacement starts with a fresh allowance.

Rate-limit headers

Every response carries the current bucket state, in two families:

Response headers

X-RateLimit-Limit: 120
X-RateLimit-Remaining: 118
RateLimit-Limit: 120
RateLimit-Remaining: 118

They describe one budget, not two: the IETF RateLimit-* pair mirrors the X- pair value for value. Read whichever your HTTP client already understands. The legacy X- pair stays for a deprecation window and will not be removed without an announcement in the changelog.

  • Name
    RateLimit-Limit / X-RateLimit-Limit
    Type
    integer
    Description

    The maximum number of requests allowed per minute for this key.

  • Name
    RateLimit-Remaining / X-RateLimit-Remaining
    Type
    integer
    Description

    Requests remaining in the current window. When it hits 0, further requests are rejected until the window resets.

The reset headers do not mirror

This is the one place the two families disagree, because they disagree about what a reset is. Both are sent only on a 429:

HeaderValueExample
X-RateLimit-ResetUnix timestamp of the moment the window resets1784729460
RateLimit-ResetDelta seconds until it resets, per the IETF draft17
Retry-AfterDelta seconds — the same number as RateLimit-Reset17

Do not treat the two Reset headers as interchangeable. 17 and 1784729460 are the same instant expressed two ways, and reading one as the other is the difference between waiting seventeen seconds and waiting until the heat death of your retry budget.

All of these are readable from a browser

X-Request-Id, Retry-After, both RateLimit families and Idempotent-Replayed are listed in Access-Control-Expose-Headers, so a cross-origin client can act on a rate limit and detect an idempotent replay rather than having them silently stripped by CORS.

When you exceed the limit

Over-limit requests return 429 with a Retry-After header (in seconds) and a rate_limit_error:

429 Too Many Requests

{
  "error": {
    "type": "rate_limit_error",
    "code": "rate_limit_exceeded",
    "message": "Too many requests. Slow down and retry after the interval in the Retry-After header."
  }
}

Guidance

  • Spread bulk work. Prefer one mass import over thousands of individual passport creations — it's dramatically fewer requests and far kinder to the limit.
  • Keys aren't a throughput multiplier. Each key has its own bucket, but issuing more keys to sidestep the limit isn't supported — a team holds at most 32 live keys. If you consistently need more headroom, contact support.
  • Watch X-RateLimit-Remaining. Slow down proactively as it approaches 0 rather than waiting for a 429.

Was this page helpful?