Errors & Status Codes

This page covers how to interpret error responses from the platform, the HTTP status codes you'll encounter, and how to approach idempotency for financial operations.

📘

A note on scope: the response envelope and error scenarios below are documented based on the generic, platform-wide API behavior. A formal, fully specified error schema for each endpoint is not yet published.

The response envelope

Successful and failed responses share a common top-level shape:

{ "status": "success", "...": "..." }
{ "status": "error", "...": "..." }

The status field tells you, at the application level, whether the operation succeeded — but you should still check the HTTP status code of the response, since that's where most of the useful detail about why a request failed actually lives (see below). Don't rely on status: "error" alone to distinguish between, say, a validation failure and a permissions problem — inspect the HTTP status code and any accompanying message.

HTTP status codes

CodeMeaning in this APIWhat to do
200Success
400 Bad RequestThe request body is malformed (e.g. invalid JSON, wrong field types)Check the request against the relevant Reference page's schema
401 UnauthorizedThe X-API-Key header is missing, invalid, or revoked — but the mTLS handshake succeededCheck your API key; see Authentication & Environments
403 ForbiddenMost commonly: your calling IP isn't allowlisted, or fails the FCrDNS check (see below). Can also indicate a compliance-state restriction on the requested operation.See IP Allowlisting & Network Security, or check the cardholder/card's current status
404 Not FoundThe requested resource (cardholder, card, wallet, OTP token, etc.) doesn't exist for this Program or, for the OTP endpoint specifically, the token has expired or is invalidConfirm the ID belongs to the Program whose credentials you're using, and that you're in the right environment (sandbox vs. production)
409 ConflictThe request conflicts with the resource's current state — for example, attempting to edit compliance-locked fields on a cardholder that's under review or approvedSee Cardholders & the Compliance Lifecycle for field-lock rules
422 Unprocessable EntityThe request is well-formed JSON but fails field-level validation (e.g. a string exceeding maxLength, an out-of-range enum value)Check field constraints (length, pattern, enum) against the relevant Reference schema
429 Too Many RequestsRate limit exceededRate limit thresholds are not currently published — see Pagination, Filtering & Rate Limits
500 Internal Server ErrorAn unexpected platform-side errorRetry with backoff; if persistent, contact support with the request details (excluding credentials)
502 / 503The platform or an upstream dependency is temporarily unavailableRetry with backoff

Known specific error scenarios

403 — "No authorized IPs configured"

This message can mean two different things, both covered in detail in IP Allowlisting & Network Security:

  1. Your calling IP genuinely hasn't been added to the allowlist for this Tenant/Program.
  2. Your IP is allowlisted, but the forward-confirmed reverse DNS (FCrDNS) check between your certificate's domains and your calling IP is failing.

Because both produce the same message, troubleshooting requires checking both the allowlist entry and your DNS configuration.

404 — OTP token invalid or expired

GET /otp/{token} and DELETE /otp/{token} return 404 if the token has expired or doesn't exist. OTP listeners are short-lived by design — see 3-D Secure and Subscribe to 3-DS One-Time Passcodes.

Troubleshooting flow

flowchart TD
    A["Request failed"] --> B{"TLS handshake<br/>completed?"}
    B -- "No" --> C["Certificate problem —<br/>see mTLS Certificates & CSRs"]
    B -- "Yes" --> D{"HTTP status?"}
    D -- "401" --> E["Check X-API-Key —<br/>see Authentication & Environments"]
    D -- "403" --> F["Check IP allowlist AND<br/>FCrDNS (DNS/PTR) —<br/>see IP Allowlisting"]
    D -- "404" --> G["Check resource ID,<br/>Program scope, and<br/>environment (sandbox vs prod)"]
    D -- "409" --> H["Check resource status —<br/>field may be compliance-locked<br/>or state may not allow this action"]
    D -- "422 or 400" --> I["Check field constraints<br/>against the Reference schema"]
    D -- "429" --> J["Back-off and retry"]
    D -- "5xx" --> K["Retry with back-off;<br/>contact support if persistent"]

Idempotency for financial operations

A complete idempotency policy has been implemented at the platform-side. The APIs do not, however, currently require an idempotency key mechanism for write operations such as deposits and transfers (POST /cards/{cardId}/bank-deposit, POST /wallets/{walletId}/bank-deposit, POST /wallets/transfer, etc.). As such, integrators might wish to implement their own idempotency policy.

🚧

Although there is an idempotency mechanism built into the platform, avoid blind retries on write operations that move funds. If a request times out or returns a 5xx, first check whether the operation actually succeeded (e.g. by querying GET /cards/transactions or GET /wallets/{walletId}) before retrying.

For read operations (all GET endpoints), retries are always safe.

What's next