Skip to main content

Errors

The API uses conventional HTTP status codes and returns a consistent JSON envelope on every error:

{
"code": "unauthorized",
"message": "Unauthorized",
"details": "The user is not authorized to perform this action"
}
codestringrequired

A stable, machine-readable error code. Branch on this, not on message.

messagestringrequired

A short human-readable summary, safe to surface to users.

detailsstring

Extra context for debugging. Wording may change — don't parse it.

Status codes

StatusMeaning
200Request succeeded.
400Malformed request — missing fields, wrong types, failed validation.
401Missing, expired or invalid access token. Refresh and retry once.
403Authenticated, but not allowed to perform this action.
404The resource doesn't exist or isn't visible to this user.
423Account locked or deactivated. The body includes a can_reactivate flag.
429Rate limited. See Rate limits — the body includes retry_after.
500Something went wrong on our side. Safe to retry with backoff.
503Temporarily unavailable — the body's code is service_unavailable. Retry with backoff.

Locked accounts

Deactivated or locked accounts return 423 with a dedicated body:

{
"reason": "account_deactivated",
"can_reactivate": true
}

When can_reactivate is true, POST /v1/auth/reactivate restores access; otherwise direct the user to support.

Retry guidance

  • Never blind-retry 4xx (except 429 after waiting retry_after) — the request itself is wrong.
  • Retry 5xx with exponential backoff and jitter.
  • On endpoints that accept an idempotency key, always retry with the same key so the operation can't double-apply.