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

# Errors

> HTTP status codes, error envelope, and common error.code values.

The API uses HTTP status codes plus a JSON error envelope. Always read both the status code and `error.code`.

## HTTP status codes

| Code | Meaning |
| - | - |
| **200** | Success. |
| **201** | A resource was created. |
| **400** | Invalid request, failed validation, or business rule (for example insufficient balance). |
| **401** | Missing or invalid secret key or credentials. |
| **403** | Authenticated, but not allowed (live key before verification or live mode, or suspended account). |
| **404** | Resource does not exist for this merchant. |
| **409** | Conflict (duplicate reference, idempotency key reused with a different body, already released). |
| **422** | Semantic validation failed (malformed payload that passed basic checks). |
| **429** | Rate limited (`RATE_LIMITED`). Back off and retry. See [Rate Limits](/guides/rate-limits). |
| **502** | Upstream provider error (banks, checkout provider). |

## Error envelope

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "success": false,
  "error": {
    "code": "INVALID_REQUEST",
    "message": "Idempotency-Key header is required for this operation",
    "details": {}
  },
  "meta": {
    "requestId": "req_01hxyz"
  }
}
```

| Field | Description |
| - | - |
| `error.code` | Stable machine readable code. Branch on this, not on the message text. |
| `error.message` | Human readable explanation. |
| `error.details` | Optional extra fields (for example `available` and `requested` on insufficient balance). |
| `meta.requestId` | Include this when you contact support. |

## Common codes

| `error.code` | Typical HTTP | When it happens |
| - | - | - |
| `UNAUTHORIZED` | 401 | No Bearer token, bad JWT, or unknown secret key. |
| `FORBIDDEN` | 403 | Live key used before verification or live mode, or action not allowed for this account. |
| `NOT_FOUND` | 404 | Unknown customer, escrow, wallet, or withdrawal for this merchant. |
| `INVALID_REQUEST` | 400 | Missing idempotency key, bad environment, or other client error. |
| `INSUFFICIENT_BALANCE` | 400 / 422 | Withdrawal larger than available, or `debitPayer: true` when the payer cannot cover the hold. |
| `GUEST_REFUND_NO_PAYMENT` | 409 | Guest refund when no successful checkout payment exists for the hold. |
| `GUEST_REFUND_PENDING` | 409 | Guest refund, release, or dispute while `pendingProviderRefund` is set. |
| `AMOUNT_MISMATCH` | 400 | Checkout or payment amount or currency does not match the hold or wallet. |
| `ESCROW_NOT_PAYABLE` | 409 | Checkout or debit against a hold that is not `awaiting_funding`. |
| `ESCROW_NOT_CANCELLABLE` | 409 | Cancel called after the hold was funded. Use refund. |
| `ESCROW_INVALID_STATE` | 409 | Release or refund while the hold is not `held` / `partially_released` (including while `disputed`). |
| `INVALID_RELEASE` / `INVALID_REFUND` | 400 | Amount exceeds remaining held funds. |
| `INVALID_DISPUTE` | 409 / 400 | Dispute opened on an unfunded hold, already resolved, or a split that does not equal remaining held. |
| `DISPUTE_EXISTS` | 409 | An open dispute already exists on this hold. |
| `DUPLICATE_REFERENCE` | 409 | Escrow or withdrawal `reference` already used on this merchant. |
| `CUSTOMER_HAS_ACCOUNT` | 409 | `DELETE /customers/{id}` when the customer already has a NUBAN. |
| `CUSTOMER_HAS_ESCROW` | 409 | `DELETE /customers/{id}` when the customer is payer, payee, or party on an escrow. |
| `BVN_NAME_MISMATCH` | 400 | BVN name does not match the customer on `POST /wallets`. |
| `PROVIDER_ERROR` | 502 | Bank resolve, identity lookup, or checkout could not be started. |
| `RATE_LIMITED` | 429 | Too many requests for this merchant. Back off. |
| Duplicate or named conflicts | 409 | Email already used, or idempotency key reused with a different body. |

Do not retry **400 / 401 / 403 / 404 / 422** blindly. Retry **502** (and timeouts) with the **same** `Idempotency-Key` on money moving `POST`s.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.