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

# Errors

> Status codes, the error shape, and what each one means.

Every error uses the same shape, so you can handle failures uniformly. The HTTP status code and `error.code` always match.

```json theme={null}
{
  "status": false,
  "error": {
    "code": 402,
    "message": "Your wallet balance is too low for this check"
  }
}
```

Some errors include an `error.details` object with extra fields. The clearest example is an insufficient funds error, which tells you the reference, the price, and your balance:

```json theme={null}
{
  "status": false,
  "error": {
    "code": 402,
    "message": "Your wallet balance is too low for this check",
    "details": {
      "reference": "43817179a3dc8c341d358432b0590924",
      "priceKobo": 5000,
      "balanceKobo": 1200
    }
  }
}
```

## Status codes

| Code  | Meaning            | Typical cause                                                                                          |
| ----- | ------------------ | ------------------------------------------------------------------------------------------------------ |
| `401` | Unauthorized       | Missing, invalid, or revoked API key.                                                                  |
| `402` | Payment required   | Wallet balance too low to cover the check.                                                             |
| `403` | Forbidden          | Organization not approved or suspended, or the scope is not active for you or not allowed by your key. |
| `404` | Not found          | No verification with that reference, or the endpoint does not exist.                                   |
| `405` | Method not allowed | Wrong HTTP method for that path.                                                                       |
| `422` | Unprocessable      | Missing or invalid inputs, or no scope in the path.                                                    |
| `500` | Server error       | An unexpected error on our side. Not charged.                                                          |
| `502` | Bad gateway        | The provider could not complete the check. Not charged.                                                |

## Which errors charge you

Only a completed check charges your wallet, and only when it returns an answer. None of the errors above debit you:

* `402`, `403`, `422` are refused **before** the provider is called.
* `500` and `502` mean the check **failed**, which is never charged.

A `502` and, in the wallet race case, a `402` include a `reference` in `error.details`, so a failed attempt is still traceable in support and in your [list](/api-reference/list-verifications).

<Warning>
  A `not_found` is **not** an error. It comes back as a normal `200` with `"status": "not_found"` in the data, and it **is** charged, because the provider gave a real answer. Do not treat `not_found` as a failure. See [the three outcomes](/concepts/how-verification-works).
</Warning>

## Authentication errors in detail

| Message                                                                         | Meaning                               |
| ------------------------------------------------------------------------------- | ------------------------------------- |
| `Missing API key. Send it in the X-Pruva-Key header.`                           | No key header present.                |
| `Invalid API key.`                                                              | The key matches no active key.        |
| `This API key has been revoked.`                                                | The key was revoked in the dashboard. |
| `This organization is not yet approved and cannot run verifications.`           | Approval is pending.                  |
| `This organization is suspended and cannot run verifications. Contact support.` | The organization is suspended.        |

## Handling errors well

<Steps>
  <Step title="Branch on status first">
    Read the top level `status` boolean. If `false`, read `error`; never assume `data` is present on a failure.
  </Step>

  <Step title="Use error.code, not the message text">
    Branch your logic on the numeric `code`. Messages are for humans and may be refined over time; the codes are stable.
  </Step>

  <Step title="Keep any reference">
    When `error.details.reference` is present, log it. It ties a failed attempt to your support request and to your verification list.
  </Step>

  <Step title="Do not loop retries">
    A `402`, `403`, or `422` will not succeed on retry without a change on your side. A `502` may be transient, but each retry is a fresh, potentially billed check, so retry once at most and reconcile from the list. See [References and retrieval](/concepts/references).
  </Step>
</Steps>
