Making a payout to a card
Creates a payout to a bank card by card number or card token.
Integration flow
- Generate a unique
transactionand choose how to pass the recipient's card. - Sign the exact request body and send the payout.
- Poll the operation status by
transactionuntil you receivecompletedorcanceled.
URL
Request
Headers
| Name | Type | Required | Description |
|---|---|---|---|
X-Api-Key |
string | Yes | Shop identifier. |
X-Signature |
string | Yes | Signature of the request body. |
Building the signature
The request must be signed with an RSA/SHA-256 electronic signature. Pass the result in the X-Signature header.
The step-by-step algorithm, key requirements, examples for Python, PHP and OpenSSL, and troubleshooting for error 20002
are given in the general section «Building a signature for payouts».
Request body
| Parameter | Type | Required | Description |
|---|---|---|---|
recipient_pan |
string | Yes | Recipient's card number, without spaces or separators. |
amount |
integer | Yes | Amount in kopecks. For example, 15000 is 150 RUB. |
transaction |
string | Yes | Unique operation identifier in the merchant's system. |
description |
string | Yes | Purpose of the payout, no more than 210 characters. |
customer |
string | No | Customer identifier — email or phone number. |
extra_data |
object | No | Additional merchant data. |
fiscal_data |
object | No | Data for receipt fiscalization under 54-FZ. |
Handling the card number
recipient_pan contains payment data. Don't log the full card number or store it unless
necessary. Comply with applicable PCI DSS requirements.
Example
Response
Choose an HTTP code to see an example, the response parameters, and the recommended actions.
If no HTTP response is received
Handle a timeout or connection loss the same way as a 5XX response: the operation result is unknown, so first
check the status by the original transaction. Don't create a new payout with a different identifier.
{
"order": {
"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"
},
"transaction": "payout-card-20260810-0001",
"status": "processing"
}
Response parameters
| Parameter | Type | Description |
|---|---|---|
order |
object | The created payout. |
∟ id |
string | Payout identifier in KVELL. |
∟ status |
string | Current payout status. Possible values are given in «Payout statuses». |
∟ transaction |
string | Operation identifier passed by the merchant. |
∟ 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 | Bank transaction identifier generated by the acquiring bank. |
∟ 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. |
transaction |
string | Operation identifier in the merchant's system. |
status |
string | Current payout status; matches order.status. |
{
"errors": [
{
"code": 20019,
"message": "Shop payout limit exceeded"
}
]
}
Response parameters
| Parameter | Type | Description |
|---|---|---|
errors |
array | List of errors. Codes and handling recommendations are given in «HTTP response errors». |
∟ code |
integer | Error code. In the example — 20019. |
∟ message |
string | Description of the reason the request was rejected. |
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. |
What this response means
The shop with the passed X-Api-Key wasn't found in the selected environment. The payout wasn't created.
{
"errors": [
{
"code": 20020,
"message": "Recipient not specified"
}
]
}
Response parameters
| Parameter | Type | Description |
|---|---|---|
errors |
array | List of validation errors. Codes and handling recommendations are given in «HTTP response errors». |
∟ code |
integer | Error code. |
∟ 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
In all of these cases, the request result is considered undefined: the payout may have been created even if the client didn't receive a response. Keep the transaction in your system in a "processing" state until you get a confirmed result from KVELL.
This scenario can occur due to a network failure, connection loss, timeout, or a technical error on the server or client side.
Unified handling algorithm
- Don't mark the payout as successful or rejected based solely on a technical error.
- Save the payout in your system in a "processing" state.
- Request the transaction status using the original
transactionvalue. - 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.
Don't create a duplicate payout
Don't resend the payout with a new transaction until the result of the original operation is established.
Payout statuses
| Status | Final | What to do |
|---|---|---|
new |
No | Poll the transaction status. |
processing |
No | Poll the transaction status. Don't create a new payout. |
completed |
Yes | The payout was completed. |
canceled |
Yes | The payout was rejected. |
A full reference of common operation statuses is given in «Transaction statuses».
OTP confirmation
Only used for shops with OTP enabled
Confirming a payout with a one-time code isn't part of the main flow. This option is enabled individually in the shop's settings. If it isn't enabled for you, you can skip this section.
When OTP is enabled, instead of the created payout object the API returns:
Response parameters
| Parameter | Type | Description |
|---|---|---|
order |
null | The payout hasn't been created yet. |
transaction |
string | Operation identifier to pass to the confirmation method. |
status |
string | wait_confirm — the payout is awaiting OTP code confirmation. |
What this response means
The request was accepted, but the payout is awaiting confirmation and hasn't yet moved to bank processing.
That's why the response has no id, amount, commission, or created_at.
What to do next
- Get the OTP code from the user.
- Pass the
transactionand the OTP code to the payout confirmation method. - After confirmation, get the final status.