JSON v3 errors: HTTP codes
The error body is the same for every code: {"success": false, "error": {"code": "…", "message": "…", "next_step": "…"}}. Branch on error., not on the texts — they may change. The “how to reproduce” column gives a ready way to get each code in the sandbox.
error. is an imperative instruction on what to do next (“take a fresh X-Timestamp”, not “invalid timestamp”): the error is read not by a human in a log but by the next iteration of your code or an AI agent. A sandbox field — the production contract does not have it, so do not rely on it in your logic.
| HTTP | error. | When | What to do | How to reproduce |
|---|---|---|---|---|
| 401 | AUTH_INVALID_SIGNATURE | The signature does not match, authentication headers are missing, the signature version is unsupported or the login is unknown — the exact reason is in error. | Recompute it by the formula; common causes are signing the wrong timestamp or stray whitespace in the secret | Replace X-Signature with 64 zeros; a request with no headers; X-Signature-Version: 2; a non-existent login |
| 401 | AUTH_INVALID_TIMESTAMP | Time drift over ±20 minutes | Take a fresh UTC timestamp; check the server clock and that the time really is UTC | An X-Timestamp a day old |
| 403 | AUTH_INVALID_PROJECT | project_id does not belong to the partner or is inactive | Use your own project_id; in the sandbox it is 1001 | /projects/999999/invoices |
| 400 | BAD_REQUEST | The POST /invoices body is not a JSON object | Send a JSON object; no invoice is created in this case | A not json body |
| 400 | TEST_CALLBACK_URL_FORBIDDEN | test_info. without the partner flag | The callback address is configured per project; ask the sandbox administrators for the flag | Send callback_url with the demo credentials |
| 409 | INVOICE_ALREADY_EXISTS | The customer already has an open invoice; its id is in error. | Read the existing invoice or cancel it instead of creating a second order | Two POST /invoices in a row for the same msisdn |
| 404 | INVOICE_NOT_FOUND | No invoice with this id in this project | Check invoice_id and project_id | GET /invoices/{random-uuid} |
| 422 | INVALID_PAYMENT_METHOD | Unknown payment_method | Allowed: sbp, sberpay_desktop, sberpay_mobile, or omit the field (card) | "payment_method": "paypal" |
| 422 | INVOICE_NOT_PAID | Refund of an unpaid invoice | Wait for payment_status: PAID | refund right after creation |
| 422 | INVOICE_NOT_AUTHORIZED | Wrong PIN; the response carries the attempts left | In the sandbox the correct PIN is 1234 | "pin_code": "0000" |
| 422 | INVOICE_AUTH_ATTEMPTS_EXCEEDED | Three PIN attempts used up — the invoice will not accept authorization again, even with the right code | Create a new invoice | Three wrong PINs in a row |
| 409 | CONTRACT_DRAFT_EXISTS | A contract with this merchant_contract_id already exists and awaits the PIN; its id is in error. | Confirm the existing contract instead of creating a second one | Two POST /contracts in a row with the same merchant_contract_id |
| 409 | CONTRACT_ALREADY_EXISTS | A contract with this merchant_contract_id is already confirmed; its id is in error. | Charge against the existing contract | POST /contracts with the number of a confirmed contract |
| 404 | CONTRACT_NOT_FOUND | The contract is unknown or cancelled | Check contract_id and project_id | POST /contracts/{random-uuid}/authorize |
| 409 | CONTRACT_ALREADY_AUTHORIZED | The contract is already confirmed | No need to confirm it again | A second authorize of the same contract |
| 422 | CONTRACT_NOT_AUTHORIZED | Wrong contract PIN | In the sandbox the correct PIN is 1234 | "pin_code": "0000" in POST /contracts/{contract_id}/authorize |
| 422 | CONTRACT_AUTH_ATTEMPTS_EXCEEDED | Three PIN attempts used up — the contract will not accept even the right code | This contract can no longer be confirmed | Three wrong PINs in a row |
Three more codes depend on settings and infrastructure: TEST_CALLBACK_URL_REJECTED and TEST_CALLBACK_URL_RATE_LIMITED reach only partners with test_info. enabled (see “Sandbox knobs”), and SERVICE_UNAVAILABLE (503) means the sandbox could not assemble the prepared response — retry the request.
{
"success": false,
"error": {
"code": "INVOICE_NOT_AUTHORIZED",
"message": "Wrong PIN, 2 attempts left"
}
}// 401 and 403 arrive in the same {success, error}
// envelope as every other error
{
"success": false,
"error": { "code": "AUTH_INVALID_SIGNATURE", "message": "…" }
}