Errors
Status codes, error bodies and retry rules shared by every API v3 endpoint. v3 only.
API v3 only
This page covers API v3, which is in preview. The 2025-04-01 and 2024-03-18 APIs behave differently (for example, they return 403 for every auth failure, where v3 splits 401 and 403). For those versions, see Error handling.
Every v3 endpoint returns some of the statuses below (403, 429 and 502 come from the Alerts endpoints only). Endpoint pages link here instead of repeating them, and list only the errors specific to that endpoint (a duplicate registration, an enrollment that already exists). The Alerts endpoints never return 409.
At a glance
| Status | code | Cause | Safe to retry? |
|---|---|---|---|
400 | malformed_request, VALIDATION_ERROR | Bad JSON, a field of the wrong type, an unknown field | No, fix the request |
401 | invalid_api_key, UNAUTHORIZED | The key is missing, malformed, revoked or wrong | No, fix the key |
403 | wrong_key_type, livemode_mismatch, merchant_not_in_portfolio | Valid key, but it can't do this | No |
404 | NOT_FOUND, plus per-endpoint codes | No such route, or no such object | No |
429 | rate_limited | Too many requests | Yes, after Retry-After |
500 | internal_error, INTERNAL_ERROR | Something failed on our side | Yes, with backoff |
502 | upstream_unavailable | A Chargeflow service behind the API is down | Yes, with backoff |
504 | upstream_timeout, REQUEST_DEADLINE_EXCEEDED | A Chargeflow service behind the API was too slow | Yes, a retried create is caught |
Error body
Every v3 error, on every endpoint, is application/json with one error object:
{
"error": {
"type": "validation_error",
"code": "enrollment_exists",
"message": "This merchant already has an enrollment for this psp and descriptor.",
"resource_id": "aen_68ce8d25b5438c0a1b2c3d4e-2b6f28f2-3ac7-46f4-85aa-501203dba38a",
"request_id": "req_8f2c1a9b4d0e"
}
}| Field | What it is |
|---|---|
type | The error class. |
code | The specific cause. Branch on this: it never changes for a given condition, message can. |
message | A human-readable explanation. |
field | The request field at fault, when there is one. |
resource_id | The existing resource the error is about, when there is one (for example, the enrollment behind enrollment_exists). |
request_id | Quote it in any support ticket. Also returned in the X-Request-ID header (Request-Id on Alerts endpoints). |
400 Bad Request
The request is malformed: invalid JSON, a field of the wrong type, or an unknown field. Nothing was written. Fix the request before sending it again. Webhook management endpoints return more specific 400 codes, listed on each endpoint.
401 Unauthorized
The key was rejected. Causes: no Authorization header, no Bearer prefix, a key not shaped cf_live_<key_id>_<secret>, or an unknown, deleted, expired or revoked key. The message is the same for all of them on purpose. Check the header and the key, then call Retrieve current key to confirm it works.
403 Forbidden
The key is valid but not allowed to do this.
| Code | When |
|---|---|
wrong_key_type | A merchant key called a platform path, named another account, or subscribed to a platform-only event. |
livemode_mismatch | A cf_test_ key reached for live data, or the reverse. |
merchant_not_in_portfolio | The chargeflow_id is not one of your merchants. Same answer whether it belongs to someone else or does not exist. |
404 Not Found
No such route (a wrong method is also 404, there is no 405), or no such object in this livemode. Object-level 404 codes are listed on each endpoint.
429 Too Many Requests
You hit the rate limit. Wait the number of seconds in Retry-After, then retry. Alerts responses carry RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset, so you can slow down before you hit it.
500 Internal Server Error
Something failed on our side; the request itself was valid. Errors from the services behind the API are never passed through: any we don't map come back as 500. Retry with exponential backoff and jitter. If it keeps failing, contact support with the request_id.
502 Bad Gateway
A Chargeflow service behind the API is not answering; the request was valid. Retry with exponential backoff and jitter.
504 Gateway Timeout
A Chargeflow service behind the API did not answer in time, and the call may still have been applied.
upstream_timeout(Alerts, 30 s): waitRetry-After, then retry. Retrying a create is safe: if the first call landed, you get422enrollment_existswith the existing enrollment's id inresource_id.REQUEST_DEADLINE_EXCEEDED(webhook management, 15 s): noRetry-After. Retry with backoff. Retrying a create is safe: if the first call landed, you get409WEBHOOK_ALREADY_EXISTS.