Standard error object
Permissio uses a single flat error envelope on every error response.
{
"error": "Human readable message",
"code": "technical_error_code",
"request_id": "uuid-v4",
"details": { "optional": "context" }
}
Code enum
Branch on code for control flow. The full set of values you may receive on a /v1/* partner endpoint is:
code | Typical status | Meaning |
|---|---|---|
validation_error | 400 | Request body or query parameters failed validation. |
not_found | 404 | The referenced resource does not exist or is not visible to your account. |
unauthorized | 401 | Generic authentication failure that does not match a more specific code. |
missing_api_key | 401 | The Authorization header was absent. |
invalid_api_key | 401 | The key was malformed, expired, revoked, or of the wrong type. |
api_key_env_mismatch | 401 | The key's sk_test_/sk_live_ prefix does not match the environment the key was issued for. Rotate to a key for the correct environment. |
ip_not_allowed | 403 | The caller IP is not on this account's IP allowlist. |
missing_scope | 403 | The key does not carry the scope required for this operation. |
forbidden | 403 | Generic authorization failure that does not match a more specific code. |
rate_limited | 429 | The account or key has exceeded its rate budget. |
internal_error | 5xx | Unexpected server error. Safe to retry with backoff. |
idempotency_conflict | 409 | The same Idempotency-Key was reused with a different request body. |
idempotency_in_progress | 425 | The same Idempotency-Key is currently being processed. Retry after a short delay. |
allowlist_check_failed | 403 | A configured allowlist (recipient domain, callback URL, etc.) rejected the request. |
The details object, when present, carries structured context such as the failing field name on a validation_error. Treat its shape as best-effort and fall back to error for display.