Reference
Errors and rate limits
Problem details with a stable code, what each status means, and how to back off.
Problem details
Errors are RFC 7807 problem details. type is a stable error code you can match on:
{ "type": "Security.InvalidApiKey", "title": "Unauthorized", "status": 401, "detail": "The provided API key is invalid or inactive." }Statuses and codes
| Status | Means | Common codes |
|---|---|---|
| 400 | Invalid input, or a wrong or expired code | Application.InvalidUrl, Application.InvalidCallbackUrl, Verification.InvalidCode, Verification.CodeExpired, Mfa.InvalidCode, Email.Empty. A missing X-Api-Key header is also a 400. |
| 401 | A bad API key, credentials or token | Security.InvalidApiKey, Security.Unauthorized, Token.InvalidOrExpired, Google.EmailNotVerified |
| 403 | Not allowed | User.Suspended, Security.AppSuspended, Verification.TooManyAttempts, Workspace.InviteOnly, SubscriptionPlan.StaffOnly, Application.LimitReached |
| 404 | Unknown app, user or session | Application.NotFound, User.NotFound, Token.SessionNotFound |
| 409 | Conflict | User.EmailInUse, Mfa.AlreadyEnabled, Database.Duplicate (another request made it first), Database.Conflict |
| 429 | Rate limited | — |
Validation errors
A request with a missing, malformed or oversized field answers 400 before anything runs. type is the first problem's code, and errors lists every field at fault with its messages:
{
"type": "Email.Invalid",
"title": "Bad Request",
"status": 400,
"detail": "Invalid email format.",
"errors": {
"email": ["Invalid email format."],
"password": ["Use at least 8 characters."]
}
}Rate limits
Rate limits are token buckets, shared by every Identise server, so a burst spread across them still counts once:
| Routes | Counted per | Limit |
|---|---|---|
/v1/oauth/*, /v1/platform/* | App (all its API keys together) | Your workspace plan's API limit a minute, with bursts of 5 seconds' worth; 1,200 a minute when the plan sets none |
| The same, without a valid API key | Client IP address | 20, refilled at 4 a second |
/v1/auth/* | Client IP address | 20, refilled at 4 a second |
/apps/{appId}/.well-known/* | Client IP address | 60, refilled at 10 a second |
A 429 carries Retry-After: the seconds until a request would get through. Need a higher limit? It comes with your workspace's plan: ask the Identise team.
Calls that check or set a password (sign-in, sign-up, resets, password changes) can also answer 429 with Retry-After: 1 during a surge, whatever your limit: hashing a password is deliberately slow, so each server takes only so many at once. Retry after the pause.
Retries
On 429, back off and retry. Retry 5xx answers and network errors with exponential backoff. Don't retry other 4xx answers: the same request will fail the same way.