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

# Errors

> How Payluk reports errors and what each status code means.

Payluk uses conventional HTTP status codes, and **every** response, including
errors, uses the [standard envelope](/introduction#the-standard-envelope). On
an error, `message` carries the reason and `data` is an empty object.

```json theme={null}
{
  "status": 400,
  "message": "Action not allowed",
  "data": {}
}
```

## Status codes

| Code  | Meaning                                                                     |
| ----- | --------------------------------------------------------------------------- |
| `200` | Success.                                                                    |
| `201` | Resource created.                                                           |
| `400` | Validation failed, action not allowed in the current state, or not found.   |
| `401` | Unauthorized: missing/invalid token, access denied, or a disallowed action. |
| `403` | Forbidden: feature not enabled, or wrong environment for the route.         |
| `500` | Server error: e.g. an action attempted by an ineligible account type.       |

<Note>
  Some validation and state errors that other APIs return as `403`/`404` are
  reported here as `400` or `401` with a descriptive `message`. Always read
  `message` rather than inferring meaning from the code alone.
</Note>

## Common messages

| Message                                                     | When it happens                                         |
| ----------------------------------------------------------- | ------------------------------------------------------- |
| `No token provided`                                         | Missing `Authorization` header.                         |
| `Access denied`                                             | The caller isn't permitted to act on this resource.     |
| `Action not allowed`                                        | The escrow isn't in a state that permits this action.   |
| `Escrow not found`                                          | No escrow matches the supplied token/ID.                |
| `customer-id header is required`                            | A customer-scoped route was called without the header.  |
| `The sum of milestone amounts must equal the escrow amount` | Milestone amounts don't add up to `amount`.             |
| `This feature is not enabled on your merchant account`      | The route needs a feature flag enabled on your account. |
| `This route is only available on staging environment`       | A staging-only helper was called on production.         |

## Handling errors

Because the HTTP code and `status` field always agree, you can branch on either.
A robust client checks `status >= 400` and surfaces `message` to logs or to the
end user.
