Docs / Reference
Error codes
Error bodies always have the same shape. Rely on code, not the message: the message is written for humans and may change.
JSON
{ "error": { "code": "duplicate_order", "message": "An invoice for this order_id already exists" } }When it's safe to retryOn
429, 500, 503, idempotency_in_progress and network errors, using the same Idempotency-Key: no duplicates will be created.Request and access
| HTTP | code | Cause and fix |
|---|---|---|
| 400 | bad_json, bad_body | Body isn't JSON, has unknown fields, or sends an amount as a number instead of a string: fix the request |
| 400 | bad_idempotency_key | Key missing or malformed: 8–128 printable ASCII characters, not starting with d: |
| 400 | bad_query | Invalid list parameters |
| 401 | unauthorized | Signature, timestamp, nonce or key problem: see CP-HMAC |
| 403 | merchant_suspended | Merchant suspended: contact support |
| 403 | merchant_not_approved | Onboarding incomplete or application under review: finish the setup wizard in the dashboard |
| 403 | billing_suspended | A fee invoice is unpaid: pay it in the dashboard under “Billing,” and the suspension lifts immediately |
| 404 | not_found | The invoice doesn't exist or belongs to someone else |
| 413 | body_too_large | Body exceeds the limit: trim metadata |
| 429 | rate_limited | Too many requests: retry with exponential backoff |
| 500 | internal | Internal error: retry with the same Idempotency-Key |
Invoices and idempotency
| HTTP | code | Cause and fix |
|---|---|---|
| 409 | duplicate_order | order_id already used: pick a new one, such as ORDER-1001-2 |
| 409 | idempotency_conflict | Same key with a different body |
| 409 | idempotency_in_progress | The first request is still running: retry in 1–2 s |
| 409 | invoice_not_payable | Invoice expired or closed: create a new one |
| 422 | invalid_order_id, invalid_price_amount, invalid_price_currency, invalid_return_url, invalid_expires_in_seconds, invalid_metadata | A field failed validation: the message explains the rule |
| 422 | invalid_allowed_assets | None of the listed assets is available: the message gives the reason for each |
| 422 | no_assets | No assets are available at all: check your wallets and assets in the dashboard |
| 422 | amount_too_small | The amount is below the minimum for every available asset |
Currency selection on the checkout page
The checkout page handles these errors. Your server only sees them if you call select yourself.
| HTTP | code | Cause |
|---|---|---|
| 409 | asset_locked | Currency change attempted after a payment |
| 409 | wallet_not_configured | No active receiving wallet on this network |
| 409 | wallet_changed, address_conflict | Retry the selection |
| 422 | asset_not_allowed | The asset isn't on the invoice or is no longer allowed |
| 503 | rate_unavailable | No confirmed rate available: offer a stablecoin |
| 503 | network_unavailable | Payments on this network are temporarily unavailable: choose another |
Refunds
| HTTP | code | Cause |
|---|---|---|
| 403 | merchant_inactive | Store suspended or key revoked |
| 409 | invoice_not_paid | No asset selected on the invoice, so there's nothing to refund |
| 409 | nothing_to_refund | Everything has already been refunded or requested |
| 409 | too_many_refunds | 20 open requests on this invoice |
| 409 | refund_executor | The platform executes this refund, not you |
| 409 | invoice_status_changed | The invoice status changed after the request: retry with "ack_status_change": true |
| 422 | amount_exceeds_refundable | Amount exceeds what's refundable: lower it or use "full" |
| 422 | invalid_amount, invalid_address, invalid_tx_hash | A field failed validation |