> ## Documentation Index
> Fetch the complete documentation index at: https://docs.instantcompliance.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Errors

> The error envelope and what each code means.

All errors share a standard envelope:

```json theme={null}
{
  "error": {
    "code": "insufficient_credits",
    "message": "Organisation has insufficient credit balance.",
    "details": { "required": 15, "balance": 4 }
  }
}
```

* **`error.code`** — stable, machine-readable identifier. Branch on this.
* **`error.message`** — human-readable summary. Suitable for logs; safe
  to surface to your end users.
* **`error.details`** — optional, code-specific extra fields.

## Codes

| HTTP | `error.code`           | When                                                                 |
| ---- | ---------------------- | -------------------------------------------------------------------- |
| 401  | `unauthorized`         | Missing / malformed / invalid / expired / revoked API key            |
| 402  | `insufficient_credits` | (v2) Action would charge credits and the balance is empty            |
| 403  | `forbidden_scope`      | Authenticated but the key lacks the scope this route needs           |
| 404  | `not_found`            | No record matching the supplied id in this organisation              |
| 409  | `conflict`             | Resource collision (e.g. email already used by another customer)     |
| 409  | `idempotency_conflict` | Idempotency-Key reused with a different request body                 |
| 422  | `validation_failed`    | Request payload failed schema validation; see `details.issues`       |
| 429  | `rate_limited`         | Burst or daily limit exceeded; honour `Retry-After`                  |
| 500  | `internal`             | Server-side error. Retry with backoff; contact support if persistent |

## `not_found` and cross-tenant isolation

A `404 not_found` is returned both when the record genuinely doesn't
exist and when it belongs to a different organisation. This is
deliberate — we never reveal whether an id belongs to another tenant.
A guessed UUID from another org always returns 404, never data.

## Validation errors

`422 validation_failed` includes per-field detail:

```json theme={null}
{
  "error": {
    "code": "validation_failed",
    "message": "Invalid customer payload.",
    "details": {
      "issues": {
        "email": ["Must be a valid email address."],
        "fullName": ["Must not be empty."]
      }
    }
  }
}
```

Surface these directly to the user who triggered the call.

## When to retry

| Code                         | Retry?                                                         |
| ---------------------------- | -------------------------------------------------------------- |
| `rate_limited`               | Yes — after `Retry-After` seconds                              |
| `internal` (500)             | Yes — with exponential backoff                                 |
| `unauthorized` (401)         | **No** — fix the key first                                     |
| `forbidden_scope` (403)      | **No** — fix the scopes first                                  |
| `validation_failed` (422)    | **No** — fix the payload first                                 |
| `conflict` (409)             | **No** — resolve the collision                                 |
| `idempotency_conflict` (409) | **No** — use a fresh idempotency key or send the original body |
| `not_found` (404)            | **No** — the resource is not there                             |
