文档以英文发布。

DocumentationPlatform

Rate limits

Per-address windows, the three headers on every response, and the one refusal code.

The windows

Limits are counted within a fixed window, per calling address unless a row says otherwise, and the bucket depends on the path:

Read from the API's configuration defaults

RoutesLimit
Everything not listed below, the well-known documents included100 per minute
POST /v1/oauth/token600 per minute, per client id rather than per address
Approving a consent on the hosted screen30 per 10 minutes
The rest of /v1/oauth/** — authorize, the hosted interaction, the cross-device poll, deny300 per minute
/v1/userinfo600 per minute
/v1/developer/** and the workspace-context reads (the developer console's own calls)300 per minute
The console's sign-in exchange (the developer SSO token route)60 per minute
Paths containing /webhooks/300 per minute
/v1/public/**120 per minute
/v1/public/document-shares/** (opening a link)30 per minute
/v1/public/document-shares/**/unlock (a password attempt)10 per 15 minutes, in a bucket of its own per address
/v1/public/privacy/requests and its email codeThe sign-in limits: 10 per 15 minutes

The numbers are deployment configuration with these defaults; a deployment may tighten them. Read the headers rather than hard-coding the table.

The OAuth and userinfo buckets

The sign-in journey is three buckets, not one. The token endpoint is keyed by your client id, so every server of one application shares 600 per minute wherever it runs, and one noisy application cannot spend another's. A request that names no client id falls back to the address.

Approving a consent spends a grant, so it is kept tight: 30 per 10 minutes per address. Everything else under `/v1/oauth/` — the authorize redirect, the hosted interaction, the cross-device status poll, a cancel — shares 300 per minute** per address, sized for an office of people behind one network polling every few seconds.

`/v1/userinfo` is read by your server with a bearer token for many people behind one address, so it has its own allowance of 600 per minute, apart from the general one. Read it once per sign-in and keep what you need; do not poll it.

A 429 on any of these means a person's sign-in fails. Watch X-RateLimit-Remaining on your own responses and treat a refusal as an alert, not a retry.

Wrong client secrets lock the client, not the address. A confidential client's failed authentications at the token endpoint are counted per client id, wherever they come from. After 10 in 10 minutes the token endpoint answers invalid_client (401) for that client until the window resets — a right secret during the lock is refused too, and a success does not reset the count. It is a 401 rather than a 429, with no Retry-After: a lock means something is guessing your secret, so rotate it rather than wait it out.

Three headers on every response

X-RateLimit-Limit
The bucket's size.
X-RateLimit-Remaining
What is left in the current window.
X-RateLimit-Reset
Unix seconds when the window ends.

They are on successful responses too, so you can slow down before you are stopped rather than after.

The refusal

Over the limit, the API answers 429 with the ordinary error envelope, code RATE_LIMIT_EXCEEDED, and a Retry-After header in seconds. Wait that long; do not retry sooner.

429
{
  "error": {
    "code": "RATE_LIMIT_EXCEEDED",
    "message": "Too many requests. Please try again later.",
    "requestId": "…",
    "details": { "retryAfterSeconds": 42 }
  }
}

What this does not do

  • Most limits are per address, not per application. A shared egress address shares a bucket. The token endpoint is the exception: it is per client id.
  • Webhook deliveries to you are not rate-limited by this. The /webhooks/ bucket is for calls you make to the API about endpoints; what UnifyID sends you is paced by its retry schedule. See Webhooks.

Verified against API commit 234dba22 on 2026-10-18. The routes, scopes, checklist, events and limits on these pages are read from that export, not typed.