Every error is JSON with a stable machine code you can branch on — never parse the human message.
{ "error": "a human-readable message (don't parse this)",
"code": "below_min", // the stable field to branch on
"detail": { "payload": { "range": { "minAmount": 0.0001651 } } } }
# detail is present only for below_min/above_max (and only when the provider returns a range).
| HTTP | code | Meaning & fix |
|---|---|---|
| 400 | below_min | Amount under the pair minimum. Read detail.payload.range.minAmount (when present), or call /estimate. |
| 400 | above_max | Amount over the pair maximum. Split into smaller orders. |
| 400 | unsupported_currency | Unknown ticker. Check /currencies. |
| 400 | unsupported_network | Coin isn't on that network. The response lists valid networks. |
| 400 | network_required | A multi-network coin (USDT, USDC…) needs an explicit fromNetwork/toNetwork. The response lists the valid networks. |
| 400 | invalid_address | Recipient/refund address failed validation for that chain (wrong-chain or malformed). |
| 400 | invalid_request | A required field is missing or malformed (bad amount, missing address, wrong type). |
| 400 | no_route | No provider can currently fill this pair. Try float, or a different pair. |
| 401 | unauthorized | Missing/invalid/revoked API key. |
| 404 | not_found | Unknown order, or not created by your key. |
| 409 | idempotency_mismatch | Reused an Idempotency-Key with a different body. Use a fresh key. |
| 400 | invalid_idempotency_key | Use 8–64 ASCII letters, digits, underscores or hyphens. A UUID is suitable. |
| 400 | invalid_extra_id / invalid_refund_extra_id | Memo/tag is invalid for its network. XRP tags must be ASCII whole numbers from 0 to 4294967295. |
| 503 | creation_pending / creation_uncertain | Creation is in progress or its result is unknown. Keep the same key and body, check Orders, or contact support before starting another order. |
| 503 | creation_safety_unavailable | The durable safety store is unavailable. Retry the same request later; do not mint a new key. |
| 429 | rate_limited | Slow down. See Retry-After. |
| 500 | internal | Our side. Safe to retry with the same Idempotency-Key. |
Send an Idempotency-Key header on every POST /exchange. It's a unique string per logical order (a UUID is ideal). Guarantees:
409 idempotency_mismatch rather than silently swapping the wrong pair.retrySameKey:true response. Changing the key can create another deposit address while the original allocation is still unresolved. Contact support if the outcome cannot be recovered.Limits are per IP. Reads are generous; order creation is tighter. On a 429 we return:
| Header | Meaning |
|---|---|
Retry-After | Seconds to wait before retrying. |
X-RateLimit-Remaining | Calls left in the current window. |
Need higher limits? Get in touch — we lift them for real integrations.