Conventions
Errors
One error shape for every API, every error code by HTTP status, and what to do about each.
Error shape
Every error has the same shape. Use code in your logic, show message to people, and quote request_id (also sent as the X-Request-Id header) when you contact support. Validation errors add field. Through passkey-x.com/api every error has this shape, whichever API answered and even when the API is briefly unreachable (502 upstream_unavailable); docs links to the code’s explanation.
{ "error": { "code": "validation_failed", "message": "nonce must be …", "request_id": "6f1c…", "field": "nonce",
"docs": "https://passkey-x.com/api-docs#error-validation_failed" } }Codes by status
| Status | Codes | What to do |
|---|---|---|
400 | invalid_jsoninvalid_parameterinvalid_bodyinvalid_idempotency_key | The body isn’t valid JSON, a parameter is out of range, or the Idempotency-Key has characters it can’t have. Fix the request. |
401 | unauthorized | The token or key is missing, expired or revoked. Refresh the session once, or use a new key. |
403 | forbiddeninsufficient_scopeip_not_allowedsession_requiredplan_requiredaddon_requiredseat_requiredsignature_requiredmfa_requiredidentity_inactive | Not allowed. forbidden (Organization API) or insufficient_scope (Customer API, see WWW-Authenticate): the key needs another scope. ip_not_allowed: the key has an IP allowlist without this address. session_required: only a signed-in session can do this (for example create keys). plan_required: the endpoint needs the Business plan. addon_required: the organization needs the add-on (Remote). seat_required: the key's owner needs a Remote seat. signature_required: an administrator must sign this Controller action in the admin console. mfa_required: use a session that completed two-step sign-in. |
404 | not_found | The resource doesn’t exist or isn’t visible to you. |
405 | method_not_allowed | The path exists but not for that method. See the Allow header. |
409 | already_existsconflictidempotency_in_progress | It already exists or was already decided (a repeated create with the same id is safe to treat as done), or the first request with this Idempotency-Key is still running: retry after Retry-After. |
410 | gone | A removed route (/v1/connectors, /v1/saas). |
412 | revision_conflict | The item changed since you read it. Fetch it, merge, re-encrypt and retry with the new ETag. |
413 | payload_too_large | The body is over 256 KB. |
415 | unsupported_media_type | Send Content-Type: application/json. |
422 | validation_failedplaintext_rejectedidempotency_key_reused | A field is invalid (see field), the body looks like plaintext secrets, or an Idempotency-Key was reused for a different request. |
429 | rate_limited | Slow down and wait Retry-After seconds, with jitter. |
500 / 502 / 503 | internal_errorupstream_unavailableservice_unavailableunavailable | Something went wrong on our side, or the service is briefly unavailable. Retry safe requests (and writes with an Idempotency-Key) with backoff. |
What to retry
- 429Wait
Retry-Afterseconds, with jitter (rate limits). - 5xx and network errorsRetry with exponential backoff: reads always, writes only with an Idempotency-Key.
- 409 idempotency_in_progressThe first request with this key is still running: retry after
Retry-After. - 401Refresh a session token once; a key that is expired or revoked needs replacing.
- Other 4xxDon’t retry: fix the request, the key’s scopes or its IP allowlist.
In the SDK
The SDK throws PasskeyXError with status, code, requestId, field, retryAfter and retryable, and retries 408, 425, 429, 5xx and network errors for you.
import { PasskeyXError } from "@passkey-x/sdk";
try {
await px.vaultItems.update(itemId, revision, envelope); // If-Match: someone else's change is never overwritten
} catch (error) {
if (error instanceof PasskeyXError) {
console.error(error.status, error.code, error.requestId); // e.g. 409 conflict, 403 insufficient_scope, 429 rate_limited
}
}Need help building on Passkey-X?
Questions about the API, a bug or a missing endpoint? Our team replies by email, usually within one business day.