Skip to content

Statuses and errors

Payment statuses

final statusesrequisites issuedexpired / canceled /not confirmedno requisites issuedpayment re-checkre-check outcomecreatedprocessingcompletedcancelederrorappeal
Status Final Meaning
created no Accepted, no requisites yet
processing no Requisites issued, waiting for the payer's transfer
completed yes Payment confirmed
canceled yes Not paid: the payment lifetime ran out, it was canceled, or the payment could not be confirmed after requisites were issued
error yes No requisites were issued, reason in error_code
appeal no A closed payment is being re-checked

A create response may already carry any status except appeal. A final status changes only after a payment re-check or a support decision — see Status changes after closing.

error happens only before requisites are issued: from created, usually right in the create response. Once requisites are issued (processing), a payment ends only as completed or canceled. If the payment cannot be confirmed after that, it also becomes canceled, with no error_code.

The payment lifetime is a project setting: 15 minutes from created_at by default. A payment not paid within it becomes canceled.

Callbacks are sent only for completed and canceled — when the payment is confirmed or canceled, when the lifetime runs out, after a payment re-check and after a support decision. There is no callback for error: you see it in the create response and when you read the payment. More in Callbacks.

error_code values

error_code and error_comment are present only for a payment in error — in the create response and when you read it. The code explains why no requisites were issued. A canceled payment has no code, including when the payment could not be confirmed. For the payer the action is always the same: pay again with a new payment and a new merchant_payment_id.

Code What happened
provider_unavailable The payment cannot be accepted now: the payment method is temporarily unavailable
provider_no_requisites No free requisites were found
rate_unavailable No exchange rate available
provider_result_ambiguous Issuing requisites was not confirmed, no requisites issued
provider_result_unknown The outcome of issuing requisites is unknown, no requisites issued
stale_dispatch Requisites could not be obtained in time
invalid_payment The payment failed field validation
json_invalid The request body could not be parsed

The list may grow: treat an unknown code as a generic failure.

HTTP errors

The error body is always JSON:

{"error": "signature_invalid"}

Content-Type: application/json; the X-Request-ID header is echoed from the request.

HTTP error When What to do
400 bad_request Not JSON, unknown field, trailing data after the object Fix the request
400 invalid_payment A field failed validation: amount, order id, geo, method, bank, callback_url, … Fix the request
401 token_invalid No token, unknown, revoked or expired token, or the project is not active Check the token in the cabinet
401 signature_invalid The signature did not verify Signing checklist
403 insufficient_scope The token lacks the scope Issue a token with payments:create / payments:read
403 ip_not_allowed The address is not in the project allowlist Add it in the cabinet
403 project_blocked Project API closed by staff Contact your manager
403 merchant_blocked Merchant is blocked Contact your manager
403 merchant_archived Merchant is deleted Contact your manager
404 payment_not_found No such payment, or it belongs to someone else Check the id
409 request_replayed This X-Request-Nonce was already used Retry with a new nonce and signature
409 payment_idempotency_conflict merchant_payment_id is taken by a payment with other fields New id, or the same fields, see Idempotency
413 request_too_large Body over the project limit (64 KB by default) Shrink the body
422 payment_not_covered Method, currency or amount outside your contract Check terms with your manager
422 payment_rate_unavailable No exchange rate Retry later with a new payment
422 payment_not_routable The payment cannot be accepted with this method right now Retry later with a new payment
429 rate_limited Rate limit exceeded Wait Retry-After seconds
429 too_many_concurrent_requests More than 20 concurrent project requests Wait Retry-After (1 s) and resend the same request
500 internal_error Server-side failure Retry with backoff
503 rate_limit_unavailable Rate accounting temporarily unavailable Wait Retry-After and retry
503 replay_protection_unavailable Nonce check temporarily unavailable Wait Retry-After and retry

If the payment was saved (in error) before a 422, the body carries its id:

{"error": "payment_not_routable", "payment_id": "3f1c2b9e-6a8d-4c4b-9a71-2c7f5d1e0a42"}

When to retry

Answer Retry? How
Timeout, dropped connection yes Same request and merchant_payment_id, new nonce and signature
429, 503 yes After Retry-After seconds, then with growing delays
500 yes With growing delays: 1, 2, 4, 8 seconds…
409 request_replayed yes With a new nonce and signature
401, 403, 400, 404, 413 no Fix the cause first
422, status error no A new attempt is a new payment with a new merchant_payment_id

Retrying with the same merchant_payment_id is safe: no second payment is created. See Idempotency and limits.

# Retry with backoff: same body and merchant_payment_id, fresh signature each time.
for attempt in range(5):
    headers = sign_request("POST", url, body, key, key_id)  # new nonce every time
    response = send(url, body, headers)
    if response.status in (429, 503):
        time.sleep(int(response.headers.get("Retry-After", "1")))
        continue
    if response.status >= 500 or response.status == 0:  # 0: timeout or dropped connection
        time.sleep(2 ** attempt)
        continue
    break