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

# Errors

> The error format and every error code.

## The envelope

Every error (except `429`, noted below) uses one JSON shape:

```json theme={null}
{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Invalid input"
  },
  "requestId": "req_8f3k2"
}
```

* **Switch on `error.code`**, never on `message` text — messages can change.
* `error.details` carries structured context and is included in non-production environments.
* Log `requestId` — include it when contacting support and we can trace the exact request.

## Error codes

| HTTP | Code                     | Meaning                                                                                               | Handling                                                                        |
| ---- | ------------------------ | ----------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- |
| 400  | `VALIDATION_ERROR`       | Bad input; also synchronous payment failures (see `details.reason`, for example insufficient balance) | Fix the request; for balance failures, top up and retry                         |
| 401  | `UNAUTHORIZED`           | Missing, invalid, or expired API key                                                                  | Check the `X-API-Key` header and key status                                     |
| 403  | `FORBIDDEN`              | Missing key scope, capability disabled, or account suspended                                          | Read the message hint; adjust key scopes or enable the capability               |
| 404  | `NOT_FOUND`              | Unknown id — **also returned for resources owned by another account**                                 | Verify the id; do not retry                                                     |
| 409  | `CONFLICT`               | `externalRef` used on the other surface, or a concurrent payment race                                 | Cross-surface ref: fix the integration. Payment race: retry after a short delay |
| 422  | `B2B_LIMIT_EXCEEDED`     | Tier limit hit — `details` identifies which                                                           | See [limits and tiers](/guides/limits-and-tiers)                                |
| 422  | `PAYMENT_ERROR`          | Payment-level failure                                                                                 | Inspect `details`; retry with a different method if appropriate                 |
| 422  | `INSUFFICIENT_BALANCE`   | Balance too low for the operation                                                                     | Top up via deposits                                                             |
| 429  | —                        | Rate limited                                                                                          | Exponential backoff                                                             |
| 502  | `EXTERNAL_SERVICE_ERROR` | Upstream provider failure                                                                             | Safe to retry with backoff                                                      |

<Note>
  The `429` response uses a flat body — `{ "error": "Too many requests", "message": "..." }` — rather than the envelope. Match on the status code.
</Note>

## Ownership returns 404, not 403

Fetching a checkout, order, deposit, or refund that belongs to another account returns `404 NOT_FOUND` — identical to a nonexistent id. This is deliberate: foreign ids do not leak existence. If you see unexpected 404s, verify you are querying the right surface (`/b2b` orders are invisible to `/retailer/v1` endpoints and vice versa).

## Retry classification

| Class                             | Retry?                                                                |
| --------------------------------- | --------------------------------------------------------------------- |
| `429`, `502`, network timeouts    | Yes, with exponential backoff — and the same `externalRef` on creates |
| `409` concurrent payment race     | Yes, after a short delay                                              |
| `400`, `401`, `403`, `404`, `422` | No — fix the underlying cause first                                   |
