429 Too Many Requests with a Retry-After directive.
Default limits
Per-key defaults are applied unless a key has an override set in the dashboard.| Key type | Default limit | Typical use |
|---|---|---|
Publishable (pk_*) | 120 requests per window | Browser SDK traffic — session setup, batch streaming, sealed-handoff minting |
Secret (sk_*) | 600 requests per window | Server-side verification, session and fingerprint readback, management endpoints |
Gate workflow credentials (gtpoll_*, agt_*) | Scoped per session | Per-session polling caps; see Gate Signup sessions |
“Per window” here refers to a rolling bucket. Burst traffic that fits within the bucket is fine; sustained traffic above the per-second equivalent of the ceiling gets throttled. For high-volume integrations — fingerprint sweeps, scoring backfills, bulk audits — contact us to raise the ceiling on a specific key.
Response headers
Every response from an authenticated endpoint includes:| Header | Value |
|---|---|
X-RateLimit-Limit | The ceiling for this key. |
X-RateLimit-Remaining | Requests left in the current window. Hits 0 on the request that would exceed the ceiling. |
| Header | Value |
|---|---|
Retry-After | Seconds until the next acceptable retry. Always honor this — further requests during the window count against the limit and can extend cooldown. |
429 response shape
Rate-limited responses use the standard error envelope:error.retryable is true on every 429, and details.next_action is always retry. The key thing the envelope doesn’t tell you is when — that’s in the Retry-After header.
Retry strategy
A correct retry for a 429 does three things: honorRetry-After, add jitter, and cap attempts.
Retry-After by default. You only need to write your own loop if you’re calling the REST API with a custom HTTP client.
What counts against the limit
Every authenticated request counts, including ones that fail:- Successful 2xx responses ✓
- 4xx client errors (wrong field, not found) ✓
- 429 responses themselves ✓
- 5xx server errors ✓
- Preflight
OPTIONSrequests ✗ (not counted)
Reducing your request rate
If you’re brushing up against the ceiling, the usual culprits and their fixes:- Per-request session verification. If you’re calling
GET /v1/sessions/:sessionIdon every authenticated API hit, you’re doing too much work. Cache the verified sealed token locally (the token already carries the verdict), and only fall back to the durable session API for audits, escalations, or stale sessions. See API abuse → Session reuse. - Manual pagination. Many integrations iterate lists by page in a
forloop. Switch to the server SDK’s auto-pagination helper, which streams items and respects retries automatically. - Unbatched management calls. If you’re provisioning many API keys or organizations, space the calls out with backoff rather than firing them concurrently.
- Polling that could be webhooks. Gate session polling uses short-lived
gtpoll_*tokens with their own caps. If you’re polling for Gate approval in a tight loop, look at the recommended polling cadence documented on Gate Signup sessions.
Raising a limit
Production integrations with sustained, legitimate load can have per-key limits raised above the defaults. Request an increase from the dashboard or by contacting support with:- The API key ID you want raised
- Your expected steady-state and peak RPS
- The endpoints you need headroom on
pk_* serves browser traffic.
What’s next
Errors
The full error envelope, including 429 details.
Pagination
Auto-pagination and filters — the main way to reduce request count.
API abuse
Session reuse patterns that reduce server-side verification rate.
Authentication
Per-key defaults and key lifecycle.