Skip to content

Errors

A refusal is always one envelope:

{
"error": {
"type": "policy_rejection",
"code": "method_suspended",
"message": "This payment method is suspended for your account.",
"param": null,
"request_id": "req_4f1c0b2e9a7d"
}
}

type is one of ten categories, each always sent on the same HTTP status, so you can branch on either. code is a stable name for the particular refusal. message is for the developer reading a log and may be reworded, so never branch on it. param names the field at fault, when there is one.

typeStatusMeaning
validation_failure400A parameter is missing or not valid. param names it.
authentication_failure401No Access Token, or one that is not valid or has expired. Get a new one at POST /oauth/token (see Authentication).
authorization_failure403The key may not act on what the request names.
not_found404No such object for this key, or no such route. Another merchant's objects read as none.
conflict409The object is not in a state that allows this.
timeout_or_in_progress409A duplicate of a request still running, or one whose outcome is not known yet, or a refund while another of the same payment is still being processed (refund_in_progress). Retry later.
policy_rejection422Your account may not do this now, for the reason in code.
invariant_violation422The request would break a rule that always holds, such as refunding more than was paid.
rate_limited429Too many requests. Wait for Retry-After seconds.
dependency_failure503Something on our side, or behind it, failed. On a read, nothing was changed; retry. On a write, whether it took effect is not known: retry with the same Idempotency-Key. See When a write answers 503.

A 503 is the one refusal that may follow work that was done: it is also what you get when something failed after a write had taken effect. So it does not say a write changed nothing.

  • A read (GET): nothing was changed. Retry after a short wait.
  • A write: whether it took effect is not known. Retry the same request with the same Idempotency-Key, and never make a new key for the retry: if the first call took effect, you are answered with its result and nothing is done twice. The payment intent calls, simulating an outcome and refunds all take that header; the webhook endpoint calls take none, and Idempotency says what a retry of each does. A terminal that records cash retries with its own idempotency_key; see Accepting cash.

Every response, an error or not, carries an X-Request-ID header, and an error carries it as request_id too. Quote it when you contact support.

Beside the codes of each operation (they are listed with it in the reference):

codetypeWhen
access_token_requiredauthentication_failureNo Access Token was sent.
invalid_access_tokenauthentication_failureThe token is not valid or has expired. Get a new one.
merchant_mismatchauthorization_failureThe key acts only for its own merchant.
test_mode_onlyauthorization_failureA test helper was called with a live key. See Testing your integration.
resource_missingnot_foundNo such object for this key.
route_missingnot_foundNo such route in this API version.
invalid_parametervalidation_failureA parameter is missing or not valid; param names it.
invalid_jsonvalidation_failureThe request body is not valid JSON.
unsupported_media_typevalidation_failureSend the body as JSON.
not_acceptablevalidation_failureThis API answers in JSON only.
method_not_allowedvalidation_failureThe resource does not take that method; Allow lists the ones it does.
rate_limitedrate_limitedToo many requests.
service_unavailabledependency_failureSomething went wrong on our side. On a read, nothing was changed; retry. On a write, whether it took effect is not known; see When a write answers 503.