Soon (v3)General

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

StatuscodeCauseSafe to retry?
400malformed_request, VALIDATION_ERRORBad JSON, a field of the wrong type, an unknown fieldNo, fix the request
401invalid_api_key, UNAUTHORIZEDThe key is missing, malformed, revoked or wrongNo, fix the key
403wrong_key_type, livemode_mismatch, merchant_not_in_portfolioValid key, but it can't do thisNo
404NOT_FOUND, plus per-endpoint codesNo such route, or no such objectNo
429rate_limitedToo many requestsYes, after Retry-After
500internal_error, INTERNAL_ERRORSomething failed on our sideYes, with backoff
502upstream_unavailableA Chargeflow service behind the API is downYes, with backoff
504upstream_timeout, REQUEST_DEADLINE_EXCEEDEDA Chargeflow service behind the API was too slowYes, a retried create is caught

Error body

Every v3 error, on every endpoint, is application/json with one error object:

Response
{
  "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"
  }
}
FieldWhat it is
typeThe error class.
codeThe specific cause. Branch on this: it never changes for a given condition, message can.
messageA human-readable explanation.
fieldThe request field at fault, when there is one.
resource_idThe existing resource the error is about, when there is one (for example, the enrollment behind enrollment_exists).
request_idQuote 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.

CodeWhen
wrong_key_typeA merchant key called a platform path, named another account, or subscribed to a platform-only event.
livemode_mismatchA cf_test_ key reached for live data, or the reverse.
merchant_not_in_portfolioThe 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): wait Retry-After, then retry. Retrying a create is safe: if the first call landed, you get 422 enrollment_exists with the existing enrollment's id in resource_id.
  • REQUEST_DEADLINE_EXCEEDED (webhook management, 15 s): no Retry-After. Retry with backoff. Retrying a create is safe: if the first call landed, you get 409 WEBHOOK_ALREADY_EXISTS.

Next step

Was this page helpful?