# Errors

The error format and every error code the API returns.


Every KleioBase API error is a JSON body with the same shape, an `error` object holding `code`, `message`, `request_id` and sometimes `details`:

```json
{
  "error": {
    "code": "validation_failed",
    "message": "limit must be between 1 and 100",
    "request_id": "req_...",
    "details": {}
  }
}
```

- `code` is stable and meant for your code to branch on.
- `message` is for people. Do not parse it.
- `request_id` also arrives in the `Request-Id` response header. Quote it if you contact support.
- `details` is present only for some errors, such as the Zod issues behind a 422.

The set of codes is open: new codes can be added without a new API version, so treat an unknown code like its status class. See [Versioning](/developers/docs/versioning).

## Codes

| Code | Status | When it happens |
|---|---|---|
| `unauthorized` | 401 | The API key is missing, malformed, unknown or revoked. |
| `forbidden` | 403 | The account has no paid plan, a read key was used for a write, or a plan limit (such as the number of people) was reached. |
| `not_found` | 404 | The workspace or resource does not exist, is in Trash, or is not yours. |
| `validation_failed` | 422 | The request is invalid. `details` explains which fields. |
| `conflict` | 409 | The request clashes with the current state: an archived workspace, a record in the wrong status, an Idempotency-Key reused with a different request, and similar. |
| `insufficient_credits` | 402 | Not enough credits to process a record. `details` has `used`, `limit`, `credits_remaining` and `shortfall`. |
| `rate_limited` | 429 | Too many requests. Wait the number of seconds in the `Retry-After` header. See [Rate limits](/developers/docs/rate-limits). |
| `internal_error` | 500 | Something went wrong on our side. Retry later and quote the `request_id` if it persists. |

## Headers on every response

- `API-Version` is the major version, currently `1`.
- `Request-Id` identifies this request.
- `Retry-After` is added to a 429.

## Retrying safely

Retry `429` after the wait, and `500` with backoff. Do not blindly retry a `422` or `409`: fix the request, or wait until the state it clashed with has changed. For writes, send an `Idempotency-Key` so a retry cannot apply the change twice. See [Idempotency](/developers/docs/idempotency).

Canonical: https://kleiobase.com/developers/docs/errors
