> ## 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](https://dev.moonpay.com/api-reference/widget/using-the-api.md#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](https://dev.moonpay.com/widget/on-ramp/customization/url-signing.md) 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](https://dev.moonpay.com/api-reference/widget/getcurrencylimits.md) |
| `5_TM_MAX_BUY_AMOUNT_EXCEEDED` | 400 | Amount above the currency's maximum | Check limits via [Get currency limits](https://dev.moonpay.com/api-reference/widget/getcurrencylimits.md) |
| `5_TM_INVALID_WALLET_ADDRESS` | 400 | Wallet address invalid for the currency | Validate against the currency's `addressRegex` from [Get currencies](https://dev.moonpay.com/api-reference/widget/getcurrencies.md) |
| `5_TM_CURRENCY_SUSPENDED` | 422 | Transactions for this currency are temporarily suspended | Retry later; check [Get currencies](https://dev.moonpay.com/api-reference/widget/getcurrencies.md) for `isSuspended` |
| `5_TM_DEFI_TOKEN_NOT_SUPPORTED` | 400 | DeFi token not supported | Check [Get DeFi tokens](https://dev.moonpay.com/api-reference/widget/getdefitokens.md) |
| `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](https://dev.moonpay.com/widget/on-ramp/customization/ip-matching.md) |
| `5_PARTNERS_IP_MISSING` | 400 | `allowedIpAddress` missing from a signed widget URL that requires it | See [IP address matching](https://dev.moonpay.com/widget/on-ramp/customization/ip-matching.md) |
| `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](https://dev.moonpay.com/api-reference/widget/getcurrencies.md) |
| `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](https://dev.moonpay.com/widget/on-ramp/customization/url-signing.md).
