Skip to main content
Every error response carries a numeric code and a stable string key. message is human-readable and may change; always branch on key.
{
  "requestId": "01900b...",
  "success": false,
  "error": { "code": 1500, "key": "INSUFFICIENT_BALANCE", "message": "..." }
}
See Error handling for retry strategy.

Code blocks

Codes are organized into 100-block ranges by domain, with sub-groups every 10 codes inside a domain.
RangeDomain
1000–1099General / Infrastructure
1100–1199Auth
1200–12992FA
1300–1399Account access
1400–1499User Settings
1500–1599Wallet
1600–1699Deposits (gateway: gatepay, onramp)
1700–1799Withdrawals (reserved)
1800–1899Crypto Deposits / Withdrawals
1900–1999Merchant Management
2000–2099Marketplace

HTTP status mapping

StatusWhen
400Generic bad request (BAD_REQUEST).
401Missing or invalid auth, including expired tokens.
403Authenticated but not permitted (suspended, IP not allowed, calling a dashboard-only route).
404Resource doesn’t exist.
409Resource conflict (idempotency replay, duplicate email, etc.).
410Gone (a one-shot 2FA code was already used).
422Validation or business-rule failure.
429Rate limited.
500Internal error.
502Upstream gateway error (Discord OAuth, marketplace partner, crypto RPC).
503Service unavailable (no marketplace workers healthy, FX unavailable, maintenance).
504Marketplace worker did not respond in time.

General / Infrastructure (1001–1007)

Cross-cutting errors that any endpoint can return.
CodeKeyHTTPMeaning
1001VALIDATION_FAILED422Request body / query failed Zod schema validation. The error includes meta.details.
1002BAD_REQUEST400Generic malformed request (e.g. unknown query combo).
1003NOT_FOUND404Generic resource not found.
1004CONFLICT409Generic uniqueness violation.
1005RATE_LIMITED429Honor Retry-After. See Rate limits.
1006INTERNAL500Catch-all server error. Retry.
1007MAINTENANCE_MODE503Service down for maintenance.

Auth (1100–1107)

CodeKeyHTTPMeaning
1100UNAUTHORIZED401No credentials.
1101INVALID_CREDENTIALS401(Dashboard JWT) bad email/password.
1102INVALID_TOKEN401(Dashboard JWT) bad signature, expired, or wrong purpose.
1103MISSING_BEARER401(Dashboard) no Authorization: Bearer header.
1104MISSING_API_KEY401No api-key header.
1105INVALID_API_KEY401Key not found.
1106API_KEY_REVOKED401Key was revoked in dashboard.
1107INVALID_REFRESH_TOKEN401(Dashboard) refresh token bad/expired.

2FA (1200–1208)

CodeKeyHTTPMeaning
1200TWOFA_REQUIRED401Login requires 2FA challenge completion.
1201INVALID_2FA_CODE422Bad TOTP / email / recovery code.
1202TWOFA_ALREADY_ENABLED409Cannot start TOTP setup; already enabled.
1203TWOFA_NOT_ENABLED422Operation requires 2FA, which isn’t on.
1204TWOFA_NOT_STARTED422TOTP setup not in progress.
1205TWOFA_USE_TOTP422Email channel offered but account uses TOTP.
1206TWOFA_USE_EMAIL422TOTP channel offered but account uses email.
1207TWOFA_CODE_USED410Recovery code already consumed.
1208TWOFA_PROVIDE_CODE422Provide a TOTP or recovery code.

Account access (1300–1311)

CodeKeyHTTPMeaning
1300FORBIDDEN403Authenticated but not permitted. Most common: API-key calling a dashboard-only route, or On-Behalf-Of set on /merchant/*.
1301ACCOUNT_SUSPENDED403Merchant or sub-user account suspended.
1302ACCOUNT_DELETED403Account is soft-deleted.
1303ACCOUNT_LOCKED403Temporarily locked (e.g. failed login bursts).
1304EMAIL_NOT_VERIFIED403Operation requires a verified email.
1305API_KEY_IP_DENIED403Source IP not on the key’s allowlist.
1306USER_NOT_OWNED403Acting on a user that doesn’t belong to your merchant.
1307USER_NOT_FOUND404Sub-user not owned by this merchant (or doesn’t exist — same response, no enumeration).
1308INVALID_INVITE422Invite token bad/expired.
1309INVITE_EMAIL_MISMATCH422Invite is for a different email.
1310INVALID_VERIFICATION422Email-verification code bad/expired.
1311CAPTCHA_FAILED403CAPTCHA verification failed.

User Settings (1400–1422)

CodeKeyHTTPMeaning
1400WRONG_PASSWORD422Current password incorrect.
1401NO_PASSWORD_SET422Account has no password (OAuth-only).
1402SAME_EMAIL422New email matches current.
1403RESTORE_INVALID422Invalid/expired restore token.
1404RESET_INVALID422Invalid/expired password reset token.
1405ACCOUNT_NOT_DELETED422Restore called on a non-deleted account.
1410TRADEURL_LIMIT422Maximum number of saved trade URLs reached.
1411TRADEURL_ALREADY_ADDED409Trade URL already saved.
1412TRADEURL_NOT_FOUND404Trade URL ID doesn’t exist.
1413TRADEURL_INVALID_TOKEN422Trade URL invalid, expired, or inventory private.
1414TRADEURL_ESCROW422Account has trade hold (escrow) enabled.
1420DISCORD_ALREADY_LINKED409Account already linked to a Discord.
1421DISCORD_NOT_LINKED422Unlink called on an unlinked account.
1422DISCORD_OAUTH_FAILED502Discord OAuth handshake failed.

Wallet (1500–1522)

CodeKeyHTTPMeaning
1500INSUFFICIENT_BALANCE422Wallet balance < required.
1501WALLET_SUSPENDED403Wallet is suspended (e.g. ledger drift).
1502WALLET_NOT_FOUND404Wallet doesn’t exist for that user/type.
1503INVALID_CURRENCY422Currency value outside the supported set.
1504INVALID_AMOUNT422Amount ≤ 0 or wrong format.
1510IDEMPOTENCY_CONFLICT409Same Idempotency-Key, different request body.
1511IDEMPOTENCY_KEY_REQUIRED422Idempotency-Key header missing on /fund.
1520TRANSFER_CURRENCY_MISMATCH422Source and destination wallets in different currencies.
1521MERCHANT_MUST_BE_USD422Merchant accounts must use USD.
1522FX_RATE_UNAVAILABLE503FX rate unavailable — retry shortly.

Deposits — gateway (1600–1608)

gatepay and onramp deposits.
CodeKeyHTTPMeaning
1600DEPOSIT_NOT_FOUND404Unknown deposit ID.
1601DEPOSIT_NOT_CANCELLABLE422Only initiated deposits can be cancelled.
1602DEPOSIT_NOT_RESUMABLE422Deposit reached a terminal state.
1603INVALID_QUOTE422Quote token bad or expired. Re-quote.
1604INVALID_CHAIN422Unsupported chain for this currency.
1605INVALID_DEPOSIT_CURRENCY422Unsupported deposit currency.
1606DEPOSIT_MIN_AMOUNT422Below provider minimum.
1607INVALID_SIGNATURE401Gateway callback signature failed.
1608GATEWAY_ERROR502Payment gateway returned an error.

Crypto deposits / withdrawals (1800–1811)

Self-hosted EVM deposit/withdrawal/transfer.
CodeKeyHTTPMeaning
1800CRYPTO_NOT_CONFIGURED503Crypto gateway not configured.
1801CRYPTO_CHAIN_NOT_SUPPORTED422Chain not enabled.
1802CRYPTO_CHAIN_PAUSED503Admin paused the chain.
1803CRYPTO_TOKEN_NOT_SUPPORTED422Token not enabled on this chain.
1804CRYPTO_ADDRESS_NOT_FOUND404No deposit address generated for user yet.
1805CRYPTO_MIN_AMOUNT422Below minimum.
1806CRYPTO_INVALID_DESTINATION422Destination address invalid.
1807CRYPTO_WITHDRAWAL_NOT_FOUND404Withdrawal not found.
1808CRYPTO_WITHDRAWAL_INVALID_STATE422Withdrawal not in a valid state for this action.
1809CRYPTO_WEBHOOK_INVALID401Webhook signature bad.
1810CRYPTO_SELF_TRANSFER422Cannot transfer to your own wallet.
1811CRYPTO_RECIPIENT_WALLET_MISSING422Recipient has no wallet for this currency.

Partner crypto payout custody (1820–1827)

CodeKeyHTTPNotes
1820CRYPTO_PAYOUT_NOT_ENABLED403Merchant does not have cryptoPayoutEnabled=true. Admin-controlled toggle.
1821CRYPTO_PAYOUT_FEE_EXCEEDS_MAX422Live fee at submission exceeds the merchant-supplied maxFeeUsdCents. No state mutated.
1822CRYPTO_PAYOUT_INSUFFICIENT_BALANCE422Per-(chain, token) sidecar balance is below amountCents + fee. Each chain × token is an independent bucket — no cross-chain liquidity.
1823CRYPTO_PAYOUT_NO_CALLBACK_URL422No active CallbackUrl registered for the merchant. Approval callbacks need somewhere to land before any withdrawal can proceed.
1824CRYPTO_PAYOUT_DUPLICATE_EXTERNAL_ID409Only on a genuine concurrent duplicate racing the first create. A normal retry of the same externalId returns the original withdrawal (idempotent replay), not this error.
1825CRYPTO_PAYOUT_INVALID_SUBUSER422forSubUser doesn’t resolve to a sub-user owned by the calling merchant. The value can be the sub-user’s UUID or your externalId, but only within your own children.
1826CRYPTO_PAYOUT_FEE_UNAVAILABLE503The gas/price oracle is temporarily down on a fee chain. Fail-closed — retry shortly.
1827CRYPTO_PAYOUT_NO_SIGNING_KEY422A webhook signing secret must be provisioned before requesting payouts, so the approval call can be signed.

Merchant management (1900–1950)

CodeKeyHTTPMeaning
1900INVALID_ADMIN_OP422Invalid admin/merchant operation.
1910APIKEY_LIMIT_REACHED422Maximum active API keys reached.
1911APIKEY_ALREADY_REVOKED422API key already revoked.
1920SECRET_ALREADY_EXISTS409Active webhook secret already exists.
1921SECRET_NOT_FOUND404Webhook secret not found.
1922SECRET_ALREADY_REVOKED422Webhook secret already revoked.
1930WEBHOOK_TEST_FAILED422Test ping didn’t return 2xx.
1931WEBHOOK_NOT_FOUND404No active callback URL configured (or revoked / disabled).
1932WEBHOOK_DELIVERY_NOT_FOUND404Delivery ID not yours / doesn’t exist.
1933WEBHOOK_URL_INVALID422URL fails SSRF / scheme checks.
1940EMAIL_TAKEN409Sub-user creation: email already registered.
1941STEAM_ID_TAKEN409Sub-user creation: Steam account already registered.
1942EXTERNAL_ID_TAKEN409Sub-user creation: externalId already taken by a different sub-user.
1943SUB_USER_HAS_BALANCE422Can’t delete: balance is non-zero.
1950INVALID_FEE_BPS422feeBps out of range (0–5000).

Marketplace (2000–2041)

CodeKeyHTTPMeaning
2000MARKET_UNAVAILABLE503No marketplace workers healthy. Retry once after 30s.
2001MARKET_TIMEOUT504Marketplace worker did not respond in time.
2002WORKER_LOW_BALANCE503Marketplace worker has insufficient balance to settle.
2010ORDER_NOT_FOUND404Trade ID or external ID doesn’t exist in your scope.
2011LISTING_NOT_FOUND404Listing sold / removed since you fetched it.
2012LISTING_DETAIL_FAILED502Failed to fetch listing details from upstream.
2020PRICE_MISMATCH409Listing price drifted above your maxPrice.
2021PRICE_BELOW_MINIMUM422Quick-buy maxPrice below current minimum listing price.
2022TRADEURL_REQUIRED422Sub-user has no primary Steam trade URL set.
2030PURCHASE_FAILED502Marketplace partner rejected the purchase.
2031PURCHASE_RETRY_TIMEOUT504Purchase retried but never settled.
2032CALLBACK_INVALID401Marketplace callback signature failed.
2040TRADE_NOT_CANCELLABLE409Trade not in a cancellable state.
2041TRADE_CANCEL_TOO_SOON422Order must be at least 30 minutes old to cancel.

Validation error shape

When key === "VALIDATION_FAILED", the error includes per-field details:
{
  "requestId": "01900b...",
  "success": false,
  "error": {
    "code": 1001,
    "key": "VALIDATION_FAILED",
    "message": "Validation failed",
    "meta": {
      "details": [
        { "path": ["amount"], "message": "Invalid decimal amount" },
        { "path": ["items", 0, "maxPrice"], "message": "String must contain at most 2 decimal places" }
      ]
    }
  }
}