Every response uses the same shape, so you handle errors the same way across the API.
// success
{ "success": true, "data": { … }, "pagination": { "limit": 50, "offset": 0, "has_more": false } }
// error
{ "success": false, "message": "human readable", "error": "machine_code", "details": { … } } Branch on the HTTP status and the machine-readable error code. message is for humans and may change. details appears on some
4xx errors and carries machine-readable context your code can act on — e.g. nft_approval_missing includes the exact transaction to send in details.nft_approval.call. pagination is only on
list endpoints. 5xx responses never leak internal detail — server-side
failures all surface as error: "internal_error".
| Status | error codes | Meaning |
|---|---|---|
| 400 | invalid_tier·missing_idempotency_key·invalid_amount·identifier_too_long | Malformed request — unknown tier, missing Idempotency-Key header, bad amount, identifier over 255 chars |
| 400 | missing_shipping_address·invalid_address·token_required·invalid_tx_hash·invalid_status·unsupported_item | Bad redemption request (invalid_address also covers a bad PUT /pool-wallet body; invalid_status also a bad ?status= filter) |
| 400 | invalid_price_query | GET /mystery/price needs exactly one of card_id / token_id |
| 402 | insufficient_funds | Custodial purchase: end-user available balance is below the tier price |
| 403 | Insufficient permissions | Key lacks the required scope (or is not a partner-scoped key) |
| 404 | not_found·token_not_found·pool_wallet_not_set | Purchase / webhook / redemption / card / token / pool wallet does not exist (or is not yours) |
| 404 | value_unknown | GET /mystery/price: card exists but no market price is available |
| 409 | idempotency_mismatch·not_fulfilled·webhook_limit | Idempotency-Key reused with a different tier_id / purchase not revealed yet / more than 20 webhooks |
| 409 | redemption_exists·not_burnable·not_owner·no_holder·no_items·invalid_status·invalid_token_id | Redemption conflict — token already redeeming, not redeemable, moved wallets, or wrong lifecycle state |
| 409 | value_unknown | Buyback: no market price available for the card |
| 409 | nft_approval_missing·card_frozen·no_holder·receiver_signature_mismatch·accept_simulation_failed | Buyback accept pre-flight — the live holder hasn’t approved the marketplace (the fix rides in details.nft_approval.call), a pending redemption/grading burn freezes the token, the token was burned, bad signature, or another on-chain rejection (a token that merely moved is followed, not failed) |
| 503 | relayer_disabled·insufficient_relayer_funds | Custodial purchasing temporarily unavailable — retry later |
Each endpoint page in the API Reference lists the exact codes it returns and when — see Purchase (custodial) or Prepare redemption.