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

# Errors

> The error response shape, the moonPayErrorCode catalog, and how to resolve common errors

Every error from the widget API is a JSON body with a stable, machine-readable `moonPayErrorCode`. This page documents the response shape, the codes you can encounter, and what to do about them.

## Error response shape

```json theme={null}
{
  "moonPayErrorCode": "4_SYS_BAD_REQUEST",
  "message": "Invalid JSON in request body",
  "type": "BadRequestError",
  "errors": []
}
```

| Field              | Type   | Description                                                                                                                                    |
| ------------------ | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| `moonPayErrorCode` | string | Stable error code, safe to branch on. Codes never change meaning once published.                                                               |
| `message`          | string | Human-readable description. May change over time; do not branch on this text.                                                                  |
| `type`             | string | The error class name, e.g. `BadRequestError`, `UnauthorizedError`, `MoonPayApiError`.                                                          |
| `errors`           | array  | Field-level validation details when the request body or parameters were invalid: `{ property, message, children }`. Empty or absent otherwise. |

## Code format

Codes follow the pattern `{category}_{space}_{name}`:

| Prefix       | Category                                                                                            |
| ------------ | --------------------------------------------------------------------------------------------------- |
| `1_SYS_`     | General system errors                                                                               |
| `4_SYS_`     | Request validation errors                                                                           |
| `5_{SPACE}_` | Domain-specific errors, e.g. `5_TM_` (transactions), `5_PS_` (payments), `5_AUTH_` (authentication) |

## System codes

These can occur on any endpoint:

| Code                         | Status | Meaning                                                                                                                                | What to do                                                                                                                           |
| ---------------------------- | ------ | -------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| `4_SYS_NOT_AUTHORIZED`       | 401    | Missing or invalid API key or token                                                                                                    | Check you're sending the right credential for the endpoint; see [Authentication](/api-reference/widget/using-the-api#authentication) |
| `4_SYS_FORBIDDEN`            | 403    | Authenticated but not permitted, often a feature that isn't enabled for your account (e.g. "Bank account verification is not enabled") | If the message names a feature, contact your account manager or support to enable it                                                 |
| `4_SYS_ACCESS_REVOKED`       | 403    | Access has been revoked                                                                                                                | Contact support                                                                                                                      |
| `4_SYS_BAD_REQUEST`          | 400    | Malformed request: invalid JSON body or failed validation                                                                              | Fix the request; check `message` and `errors`                                                                                        |
| `4_SYS_NOT_FOUND`            | 404    | Resource not found                                                                                                                     | Check the identifier; for customers, they must have at least one session initiated with your key                                     |
| `4_SYS_NOT_ALLOWED`          | 405    | HTTP method not allowed                                                                                                                | Use the method documented on the endpoint page                                                                                       |
| `4_SYS_CONFLICT`             | 409    | Request conflicts with current resource state                                                                                          | Re-fetch the resource and check its state                                                                                            |
| `4_SYS_UNPROCESSABLE_ENTITY` | 422    | Input is well-formed but semantically invalid                                                                                          | Fix the request; check `message`                                                                                                     |
| `4_SYS_TOO_MANY_REQUESTS`    | 429    | Rate limited                                                                                                                           | Retry with exponential backoff                                                                                                       |
| `4_SYS_NOT_IMPLEMENTED`      | 501    | Endpoint path not implemented                                                                                                          | Check the URL; contact support if it matches the docs                                                                                |
| `1_SYS_UNKNOWN`              | varies | See below                                                                                                                              | See below                                                                                                                            |

## `1_SYS_UNKNOWN` is not always a server error

`1_SYS_UNKNOWN` means the error didn't carry a specific code. **The HTTP status tells you whose problem it is:**

* **With a 4xx status**, it is a validation error from an older code path. The `message` is accurate and actionable; treat it exactly like a `4_SYS_*` error. For example, URL signing failures return `400` with `1_SYS_UNKNOWN` and messages like `Invalid signature`, `Missing signature`, or `Invalid API key`. That means your [URL signing](/widget/on-ramp/customization/url-signing) implementation needs fixing, not that MoonPay had an internal error.
* **With a 500 status**, it is a genuine unexpected error on MoonPay's side. The message is `Internal Server Error`. Retry with backoff; if it persists, contact support with the request details and timestamp.

## Common domain codes

Domain codes (`5_*`) are stable and their messages are descriptive. The ones you'll most commonly encounter:

| Code                                | Status | Meaning                                                               | What to do                                                                                                |
| ----------------------------------- | ------ | --------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- |
| `5_DP_LIVE_MODE_DISABLED`           | 403    | Live API key used against the sandbox environment                     | Use your `pk_test_`/`sk_test_` keys on sandbox                                                            |
| `5_TM_MIN_BUY_AMOUNT_NOT_MET`       | 400    | Amount below the currency's minimum                                   | Check limits via [Get currency limits](/api-reference/widget/getcurrencylimits)                           |
| `5_TM_MAX_BUY_AMOUNT_EXCEEDED`      | 400    | Amount above the currency's maximum                                   | Check limits via [Get currency limits](/api-reference/widget/getcurrencylimits)                           |
| `5_TM_INVALID_WALLET_ADDRESS`       | 400    | Wallet address invalid for the currency                               | Validate against the currency's `addressRegex` from [Get currencies](/api-reference/widget/getcurrencies) |
| `5_TM_CURRENCY_SUSPENDED`           | 422    | Transactions for this currency are temporarily suspended              | Retry later; check [Get currencies](/api-reference/widget/getcurrencies) for `isSuspended`                |
| `5_TM_DEFI_TOKEN_NOT_SUPPORTED`     | 400    | DeFi token not supported                                              | Check [Get DeFi tokens](/api-reference/widget/getdefitokens)                                              |
| `5_QC_BUY_QUOTE_INVALID_SIGNATURE`  | 400    | Quote signature invalid: the quote was tampered with or expired       | Fetch a fresh quote and pass its signature through unchanged                                              |
| `5_PARTNERS_IP_MISMATCH`            | 400    | Customer IP doesn't match `allowedIpAddress` on the signed widget URL | See [IP address matching](/widget/on-ramp/customization/ip-matching)                                      |
| `5_PARTNERS_IP_MISSING`             | 400    | `allowedIpAddress` missing from a signed widget URL that requires it  | See [IP address matching](/widget/on-ramp/customization/ip-matching)                                      |
| `5_PS_PAYMENT_METHOD_NOT_AVAILABLE` | 400    | Payment method not available for this customer/currency/region        | Offer an alternative payment method                                                                       |
| `5_PS_CURRENCY_NOT_SUPPORTED`       | 400    | Currency not supported for this operation                             | Check [Get currencies](/api-reference/widget/getcurrencies)                                               |
| `5_IS_LIMIT_EXCEEDED`               | 400    | Transaction amount exceeds the customer's daily limit                 | Surface the limit to the customer; limits depend on KYC level                                             |
| `5_IS_SCA_REQUIRED`                 | 400    | Strong customer authentication required                               | Direct the customer through the widget flow                                                               |

If you hit a `5_*` code that isn't listed here, the `message` describes the cause. The code is stable, so it's safe to handle specific cases in your integration.

## Worked examples

**`403` + `4_SYS_FORBIDDEN` + "Bank account verification is not enabled"**: your account doesn't have the named feature enabled. No request change will fix it; ask your account manager or support to enable bank account verification.

**`400` + `1_SYS_UNKNOWN` + "Invalid signature"**: your widget URL signature doesn't match what MoonPay computes. Verify you're signing the exact query string (after URL encoding) with your **secret** key, HMAC-SHA256, base64-encoded; see [URL signing](/widget/on-ramp/customization/url-signing).
