Provenance

Rate limits

Limits are enforced per API key using a sliding window. (In production this is backed by Redis; the hosted sandbox uses an in-memory window.)

Limits

| Scope of request | Limit | | --- | --- | | Default | 100 / 60s | | verify | 500 / 60s | | attest | 200 / 60s | | escalate | 20 / 60s |

/v1/media/screen additionally enforces 10 / hour per IP on top of the per-key limit, because screening spends a real external budget.

Who a limit is counted against

| Caller | Bucket | | --- | --- | | API key | the key | | Signed-in dashboard session (cookie) | the session, so colleagues behind one office IP don't share a limit | | No credential (public pages, keyless endpoints, magic-link sign-in) | the client IP |

A cookie that doesn't resolve to a live session is counted against the IP. Sign-in (/v1/auth/magic-link) also keeps its own per-email limit of 5 per 15 minutes.

Headers

Every response, including 200s, carries:

X-RateLimit-Limit: 100
X-RateLimit-Remaining: 99
X-RateLimit-Reset: 1783132956

On a 429 you also get Retry-After (seconds) and the rate_limit_exceeded error body.

Backoff guidance

When you receive a 429, wait for Retry-After seconds, then retry with exponential backoff and jitter. Don't hammer the reset boundary — read X-RateLimit-Remaining and pace yourself before you're throttled.