Confirming a card payout
Confirms with an OTP code a card payout for which the creation method returned status: wait_confirm.
This method is only used for shops with OTP payout confirmation enabled.
Integration flow
- Get the
transactionfrom the response of the payout method. - Get the OTP code via the channel configured for the shop: SMS or email.
- Sign the exact JSON body and send the
transactiontogether with the OTP code. - If the payout moves to
neworprocessing, poll the transaction status method every 2 minutes, or use a callback, until you get a final status.
OTP code validity period
By default, the OTP code is valid for 15 minutes from the moment it's generated. The actual period may depend on the shop's settings. After it expires, confirmation with that code will fail.
Difference from confirming an SBP payout
The request body, response schema, and signature generation match the SBP payout confirmation. The URL differs:
for a card payout, /v1/orders/account2card/confirm is used.
URL
Request
Headers
| Name | Type | Required | Description |
|---|---|---|---|
X-Api-Key |
string | Yes | Shop identifier. Use the same key used to create the payout. |
X-Signature |
string | Yes | Signature of the exact request body. |
Building the signature
The request is signed with the same RSA/SHA-256 algorithm used for creating a card or SBP payout.
The step-by-step algorithm is given in the general section «Building a signature for payouts».
Request body
| Parameter | Type | Required | Description |
|---|---|---|---|
transaction |
string | Yes | Operation identifier from the response of the payout method. |
otp |
string | Yes | One-time confirmation code. A numeric value can be passed as a string or a number. |
Example
Response
Choose an HTTP code to see an example, the response parameters, and the recommended actions.
If no HTTP response is received
The confirmation result is unknown: the payout may have been created. Don't send a new payout or request a new
OTP code until you check the status by the original transaction.
{
"id": "3b3c19f4-c680-4f5d-bf2e-c0835439cf12",
"status": "processing",
"transaction": "payout-card-20260810-0001",
"amount": 15000,
"commission": 150,
"description": "Payout under contract 42",
"additional_data": {
"auth_code": null,
"rrn": null
},
"error_code": null,
"error_message": null,
"created_at": "2026-08-10T09:15:27.231000+00:00"
}
Response parameters
| Parameter | Type | Description |
|---|---|---|
id |
string | Payout identifier in KVELL. |
status |
string | Current payout status. Possible values are given in «Transaction statuses». |
transaction |
string | Operation identifier in the merchant's system. |
amount |
integer | Payout amount in kopecks. |
commission |
integer | Commission in kopecks. |
description |
string | null | Purpose of the payout. May include a prefix configured for the shop. |
additional_data |
object | null | Additional data received while processing the payout. |
∟ auth_code |
string | null | Authorization code, if returned by the bank. |
∟ rrn |
string | null | Operation identifier in the payment system, if generated. |
error_code |
string | null | Rejection reason code. Possible values are given in «Transaction error codes». |
error_message |
string | null | Description of the rejection reason. Returns null for a payout that wasn't rejected. |
created_at |
string | Date and time the payout was created, in ISO 8601 format. |
What this response means
The OTP code was accepted, the payout was created. HTTP code 200 doesn't mean the payout completed
successfully: the business result is determined by the status field.
{
"errors": [
{
"code": 20004,
"message": "Session not found"
}
]
}
Response parameters
| Parameter | Type | Description |
|---|---|---|
errors |
array | List of errors. Codes and handling recommendations are given in «HTTP response errors». |
∟ code |
integer | Error code. For a missing confirmation session — 20004; for an invalid signature — 20002. |
∟ message |
string | Description of the reason the request was rejected. |
What this response means
Code 20004 means the payout data for the specified transaction wasn't found or is no longer available.
The payout wasn't created at this step.
Response parameters
| Parameter | Type | Description |
|---|---|---|
errors |
array | List of errors. Codes and handling recommendations are given in «HTTP response errors». |
∟ code |
integer | Error code. For access denial — 20037. |
∟ message |
string | Description of the reason for the access denial. |
Response parameters
| Parameter | Type | Description |
|---|---|---|
errors |
array | List of errors. Codes and handling recommendations are given in «HTTP response errors». |
∟ code |
integer | Error code. For a shop that wasn't found — 20006. |
∟ message |
string | Description of why the resource wasn't found. |
{
"errors": [
{
"code": 20098,
"message": "otp: Field required"
}
]
}
Response parameters
| Parameter | Type | Description |
|---|---|---|
errors |
array | List of validation errors. Codes and handling recommendations are given in «HTTP response errors». |
∟ code |
integer | Field error code — 20098. |
∟ message |
string | Reason for the validation error. |
{
"errors": [
{
"code": 20000,
"message": "Unknown error"
}
]
}
Response parameters
| Parameter | Type | Description |
|---|---|---|
errors |
array | List of errors. Codes and handling recommendations are given in «HTTP response errors». |
∟ code |
integer | Error code. For an unknown error — 20000. |
∟ message |
string | Description of the technical error. |
5XX, timeout, and connection loss
The confirmation result is unknown: the payout may have been created and sent for processing.
Unified handling algorithm
- Don't resend the confirmation or create a new payout based solely on a technical error.
- Request the transaction status using the original
transaction. - If the transaction is found, keep checking it until you receive a final status.
- If status requests keep failing, contact support and provide the
transaction.