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

# Errors

Every `4xx` and `5xx` response from the Payouts API carries a structured error body so you can handle failures programmatically. For the HTTP status codes themselves, see [Status Codes](/docs/status-codes).

## Error response shape

Every error response - for any `4xx` or `5xx` - has the same JSON body: a single `error` object.

```json theme={null}
{
  "error": {
    "type": "invalid_request_error",
    "code": "VALIDATION_ERROR",
    "message": "One or more request fields failed validation.",
    "details": {
      "amount": "must be greater than 0"
    }
  }
}
```

| Field     | Type   | Description                                                                                                                       |
| --------- | ------ | --------------------------------------------------------------------------------------------------------------------------------- |
| `type`    | string | Coarse, machine-readable error **category**. Branch on this to handle a whole class of failures without enumerating every `code`. |
| `code`    | string | Specific, machine-readable error **code**. Use this when you need to react to a particular failure.                               |
| `message` | string | Human-readable description of what went wrong. Intended for logs and debugging - do not parse it.                                 |
| `details` | object | *Optional.* Additional context, such as field-level validation failures. Present only when there is extra context to convey.      |

<Note>
  Build your error handling against `type` and `code`, never against `message`. Messages are meant for humans and may change at any time; the `type` and `code` values are stable contracts.
</Note>

## Error types

`type` groups every error into one of the following categories. It maps directly to the HTTP status class, so you can branch on either.

| `type`                      | HTTP status                 | Meaning                                                                |
| --------------------------- | --------------------------- | ---------------------------------------------------------------------- |
| `invalid_request_error`     | `400 Bad Request`           | The request was malformed or a field failed validation.                |
| `authentication_error`      | `401 Unauthorized`          | Credentials are missing or invalid.                                    |
| `authorization_error`       | `403 Forbidden`             | The credentials are valid but not permitted to perform this operation. |
| `not_found_error`           | `404 Not Found`             | The requested resource does not exist.                                 |
| `conflict_error`            | `409 Conflict`              | The request conflicts with the current state of the resource.          |
| `rate_limit_error`          | `429 Too Many Requests`     | Too many requests were sent in a given window. Back off and retry.     |
| `service_unavailable_error` | `503 Service Unavailable`   | A dependency is temporarily unavailable. Retry the request.            |
| `internal_error`            | `500 Internal Server Error` | An unexpected error occurred on our side.                              |

## Error codes

The full set of `code` values, grouped by `type`.

### `invalid_request_error` - `400`

| `code`                        | Description                                                                          |
| ----------------------------- | ------------------------------------------------------------------------------------ |
| `VALIDATION_ERROR`            | One or more request fields failed validation. See `details` for field-level context. |
| `INVALID_ACCOUNT_TYPE`        | The account type is not supported for this operation.                                |
| `INVALID_DELIVERY_PREFERENCE` | The requested delivery preference is not valid for this delivery method.             |
| `MCC_REQUIRED`                | A merchant category code (MCC) is required for this payment.                         |
| `GOODS_RECEIVED_REQUIRED`     | Confirmation that goods/services were received is required for this payment.         |
| `IDEMPOTENCY_KEY_REQUIRED`    | The `Idempotency-Key` header is required for this request.                           |
| `FEE_CALCULATION_FAILED`      | Fees could not be calculated for the supplied request.                               |

### `authentication_error` - `401`

| `code`         | Description                     |
| -------------- | ------------------------------- |
| `UNAUTHORIZED` | Missing or invalid credentials. |

### `authorization_error` - `403`

| `code`                  | Description                                                                                  |
| ----------------------- | -------------------------------------------------------------------------------------------- |
| `BUSINESS_NOT_ELIGIBLE` | The business is restricted (by a risk/compliance limitation) from performing this operation. |

### `not_found_error` - `404`

| `code`      | Description                            |
| ----------- | -------------------------------------- |
| `NOT_FOUND` | The requested resource does not exist. |

### `conflict_error` - `409`

| `code`                        | Description                                                                           |
| ----------------------------- | ------------------------------------------------------------------------------------- |
| `NO_ACTIVE_API_KEY`           | The partner has no active API key to bind the webhook registration to.                |
| `DUPLICATE_ENTITY`            | An entity with these identifiers already exists.                                      |
| `DUPLICATE_ACCOUNT`           | An account with these identifiers already exists.                                     |
| `DUPLICATE_PAYMENT`           | A payment with these identifiers already exists.                                      |
| `DUPLICATE_EXTERNAL_ID`       | The supplied `externalId` is already in use.                                          |
| `ACCOUNT_IN_USE`              | The account is still referenced by other resources and cannot be modified or removed. |
| `PAYMENT_NOT_EDITABLE`        | The payment can no longer be modified in its current state.                           |
| `PAYMENT_NOT_CANCELABLE`      | The payment has begun processing and can no longer be canceled.                       |
| `IDEMPOTENCY_KEY_REUSED`      | The `Idempotency-Key` was reused with a different request body.                       |
| `IDEMPOTENCY_KEY_IN_PROGRESS` | Another request with this `Idempotency-Key` is still being processed.                 |

### `service_unavailable_error` - `503`

| `code`                          | Description                                                          |
| ------------------------------- | -------------------------------------------------------------------- |
| `IDEMPOTENCY_STORE_UNAVAILABLE` | The idempotency store is temporarily unavailable; retry the request. |

### `internal_error` - `500`

| `code`           | Description                   |
| ---------------- | ----------------------------- |
| `INTERNAL_ERROR` | An unexpected error occurred. |

<Warning>
  For any `5xx` response the `message` is always the generic `"An unexpected error occurred"` and the `code` is always `INTERNAL_ERROR`, regardless of the underlying cause - internal details are never echoed back to the caller. Rely on the HTTP status class to detect server-side failures, and contact support with your request context if they persist.
</Warning>

## Idempotency

Write operations accept an `Idempotency-Key` request header. Sending the same key again returns the original result instead of performing the operation twice, which makes it safe to retry after a network error or a `5xx`.

* Reusing a key with a **different** request body returns `409 conflict_error` / `IDEMPOTENCY_KEY_REUSED`.
* Retrying while the first request is **still in flight** returns `409 conflict_error` / `IDEMPOTENCY_KEY_IN_PROGRESS` - wait and retry.
* If the idempotency store is temporarily down, you'll get `503 service_unavailable_error` / `IDEMPOTENCY_STORE_UNAVAILABLE` - retry the request.
