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
| Code | Meaning in this API | What to do |
|---|---|---|
| 200 | Success | — |
| 400 Bad Request | The request body is malformed (e.g. invalid JSON, wrong field types) | Check the request against the relevant Reference page's schema |
| 401 Unauthorized | The X-API-Key header is missing, invalid, or revoked — but the mTLS handshake succeeded | Check your API key; see Authentication & Environments |
| 403 Forbidden | Most 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 Found | The 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 invalid | Confirm the ID belongs to the Program whose credentials you're using, and that you're in the right environment (sandbox vs. production) |
| 409 Conflict | The request conflicts with the resource's current state — for example, attempting to edit compliance-locked fields on a cardholder that's under review or approved | See Cardholders & the Compliance Lifecycle for field-lock rules |
| 422 Unprocessable Entity | The 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 Requests | Rate limit exceeded | Rate limit thresholds are not currently published — see Pagination, Filtering & Rate Limits |
| 500 Internal Server Error | An unexpected platform-side error | Retry with backoff; if persistent, contact support with the request details (excluding credentials) |
| 502 / 503 | The platform or an upstream dependency is temporarily unavailable | Retry 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:
- Your calling IP genuinely hasn't been added to the allowlist for this Tenant/Program.
- 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 queryingGET /cards/transactionsorGET /wallets/{walletId}) before retrying.
For read operations (all GET endpoints), retries are always safe.
