SBP payout with currency conversion
A payout to an individual via SBP with the option to specify the amount in a currency other than
the shop's currency. If currency is passed, the amount is automatically converted into the
shop's currency before being sent to the bank — in logic and request parameters, this method
is identical to «Making a payout via SBP», plus a conversion step.
When to use this method instead of the base one
Use this method if the payout amount is originally in a currency other than the shop's
currency (for example, the shop settles in dollars, but payouts go out in rubles). If
currency is not passed, the method behaves identically to the
base SBP payout method — no conversion is performed.
Integration flow
- Get the recipient bank's
bank_idfrom the general list of banks or from the list of banks by phone number. - If needed, call the payout feasibility check with conversion and wait for the result via the check status method.
- Generate a unique
transaction. If the payout amount is in a currency other than the shop's currency, pass its numeric ISO 4217 code in thecurrencyfield — the amount will be automatically recalculated before the payout. See «Currency codes». - Sign the exact request body (including the
currencyfield, if passed) and send the payout. - Poll the operation status by
transactionuntil you receivecompletedorcanceled.
When a preliminary check is needed
A check lets you make sure in advance that the bank can accept the payout, and lets you obtain
nspk_id and request_id. For payouts via Alfa-Bank, pass the obtained nspk_id if a check
was performed before creating the payout.
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. The exact bytes of the
request body being sent are signed, including the currency field, if passed. 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 |
|---|---|---|---|
phone |
string | Yes | Recipient's phone number: 11 digits, without +, spaces, or separators. Example: 79991234567. |
fio |
string | Yes | Recipient's full name. For banks that don't accept Ё/ё, use the agreed-upon variant with Е/е. |
bank_id |
string | Yes | Bank identifier from the list of banks or the list of banks by phone. |
amount |
integer | Yes | Amount in the minor units of the currency specified in currency (kopecks for rubles, cents for dollars, etc.). If currency is not passed, the amount is in the minor units of the shop's payout profile currency. For example, 15000 is 150.00 in the corresponding currency. |
transaction |
string | Yes | Unique operation identifier in the merchant's system. |
description |
string | Yes | Purpose of the payout, no more than 110 characters. |
currency |
string | No | Numeric ISO 4217 code of the source currency as a string, e.g. "840" for USD. If not passed, amount is assumed to be in the shop's currency — no conversion is performed. See «Currency codes». |
fio_check |
boolean | No | true — check that the passed full name matches the full name received from NSPK. |
bank_bic |
string | Conditional | BIC from the response of the bank list method. Whether it's required depends on the configured acquiring bank. |
nspk_id |
string | Conditional | Payment link obtained at the stage of calling the payout feasibility check status method. If not included in the request, the link will be obtained via a separate request to NSPK as part of processing the payment. Required for working via Alfa-Bank if payout feasibility check methods were called beforehand. |
request_id |
string | Conditional | Identifier of the payout feasibility check request. Whether it's required depends on the configured acquiring bank. |
customer |
string | No | Customer's email or phone number in the merchant's system. |
extra_data |
object | No | Additional merchant data. |
fiscal_data |
object | No | Data for receipt fiscalization under 54-FZ. |
Conditional parameters
Whether request_id and bank_bic are required depends on the acquiring bank through which
the shop's payouts are configured. If the integration scheme is unknown, check with your
KVELL account manager before launching in Production.
request_id from a preliminary check without currency
If you called the payout feasibility check with conversion and
received a request_id, when creating the payout itself you still need to pass amount in
the source currency together with the currency field — request_id does not automatically
carry over the conversion result.
Example
Response
Select the HTTP code to see an example, the response parameters, and recommended actions.
If no HTTP response is received
Handle a timeout or connection loss the same way as a 5XX response: the result of the
operation is unknown, so first check the status by the original transaction. Do not create a
new payout with a different identifier.
{
"id": "3b3c19f4-c680-4f5d-bf2e-c0835439cf12",
"status": "processing",
"transaction": "payout-20260806-0001",
"amount": 853846,
"commission": 8538,
"description": "Выплата по договору 42",
"additional_data": null,
"error_code": null,
"error_message": null,
"created_at": "2026-08-06T09:15:27.231000+00:00"
}
Response parameters
| Parameter | Type | Description |
|---|---|---|
id |
string | Payout identifier in KVELL. |
status |
string | Payout status. Possible values are given in «Payout statuses». |
transaction |
string | Operation identifier passed by the merchant in the request. |
amount |
integer | Payout amount in the minor units of the shop's currency. If currency was passed, this is the conversion result, not the value from the request. |
commission |
integer | Commission in the minor units of the shop's currency. |
description |
string | null | Purpose of the payout. |
additional_data |
object | null | Additional operation data, if generated during processing. |
error_code |
string | null | Cancellation reason code. Possible values are given in «Transaction error codes». null for an incomplete payout. |
error_message |
string | null | Description of the cancellation reason. null for an incomplete payout. |
created_at |
string | Date and time the payout was created, in ISO 8601 format. |
The conversion result is not returned in the response
The response does not contain an fx_conversion object — use the amount field to find
out the amount actually paid out in the payout profile currency. If you need the rate and
intermediate conversion values right before the payout, call
«Payout feasibility check with conversion» in advance — it
returns an fx_conversion object in the response.
{
"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». |
errors[].code |
integer | Error code. In the example — 20019. |
errors[].message |
string | Description of why the request was rejected. |
The limit is checked already in the payout profile currency
If currency was passed, the shop's payout limit check is performed after
conversion — against the final amount in the payout profile currency, not against the
amount value from the request.
Response parameters
| Parameter | Type | Description |
|---|---|---|
errors |
array | List of errors. Codes and handling recommendations are given in «HTTP response errors». |
errors[].code |
integer | Error code. In the example — 20037. |
errors[].message |
string | Description of why access was denied. |
{
"errors": [
{
"code": 20006,
"message": "Shop not found"
}
]
}
{
"errors": [
{
"code": 20045,
"message": "The shop's payout profile has no currency set"
}
]
}
{
"errors": [
{
"code": 20044,
"message": "The integration with Montra is not configured for the shop"
}
]
}
Response parameters
| Parameter | Type | Description |
|---|---|---|
errors |
array | List of errors. Codes and handling recommendations are given in «HTTP response errors». |
errors[].code |
integer | 20006 — shop not found; 20045 — the shop's payout profile has no currency set; 20044 — the integration with the rates provider is not configured. |
errors[].message |
string | Description of why the resource was not found. |
What this response means
20006 — the shop with the given X-Api-Key was not found in the selected
environment, the payout was not created.
20045 and 20044 occur only if currency was passed: the amount cannot be
converted, the payout was not created. For 20045, contact KVELL support to set the
payout profile currency. For 20044, contact KVELL support to connect the rates provider
integration for the shop.
{
"errors": [
{
"code": 20098,
"message": "amount: Field required"
}
]
}
Response parameters
| Parameter | Type | Description |
|---|---|---|
errors |
array | List of validation errors. Codes and handling recommendations are given in «HTTP response errors». |
errors[].code |
integer | Error code. For a field error — 20098. |
errors[].message |
string | Reason for the validation error. |
Currency field format
currency must consist of 1-3 digits (^\d{1,3}$). Letter currency codes ("USD") are
rejected with error 20098.
{
"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». |
errors[].code |
integer | Error code. For an unknown error — 20000. |
errors[].message |
string | Description of the technical error. |
5XX, timeout, and connection loss
In all of these cases, the result of the request is considered undefined: the payout may have been created even if the client did not receive a response. Keep the transaction in your system in a "processing" state until you receive 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
- Do not mark the payout as successful or rejected based solely on a technical error.
- Keep 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 get a final status.
- If status requests keep failing, contact support and provide the
transaction.
Do not create a duplicate payout
Do not resend the payout with a new transaction until the result of the original
operation has been established.
Payout statuses
The full status reference is given in the «Payout statuses» section of the base method — for payouts with currency conversion, they are no different.
Confirmation via OTP
Used only for shops with OTP enabled
Payout confirmation via a one-time code is not part of the main flow. This option is enabled individually in the shop settings. If it is not enabled for you, you can skip this section.
With OTP enabled, instead of the created payout object, the API returns:
Response parameters
| Parameter | Type | Description |
|---|---|---|
status |
string | Status wait_confirm: the payout is waiting for OTP confirmation. |
transaction |
string | Operation identifier that must be passed to the confirmation method. |
What this response means
The request has been accepted, but the payout is awaiting confirmation and has not yet moved
to bank processing. That's why the response does not contain id, amount, commission, or
created_at.
The conversion result is preserved until confirmation
If currency was passed, the conversion result is stored together with the confirmation
session and is automatically applied when calling the confirmation method — there is no need
to pass currency again.
What to do next
- Obtain the OTP code from the user.
- Pass
transactionand the OTP code to the payout confirmation method (this method is shared for payouts with and without currency conversion; there is no separate v2 confirmation method). - After confirmation, retrieve the final status.