Skip to content

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

  1. Get the transaction from the response of the payout method.
  2. Get the OTP code via the channel configured for the shop: SMS or email.
  3. Sign the exact JSON body and send the transaction together with the OTP code.
  4. If the payout moves to new or processing, 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

POST https://api.pay.kvell.group/v1/orders/account2card/confirm
POST https://api.pay.stage.kvell.group/v1/orders/account2card/confirm

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

{
  "transaction": "payout-card-20260810-0001",
  "otp": "123456"
}

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.

200 (OK) response example
{
  "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.

400 (Bad Request) response example
{
  "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.

403 (Forbidden) response example
{
  "errors": [
    {
      "code": 20037,
      "message": "Access denied"
    }
  ]
}

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.
404 (Not Found) response example
{
  "errors": [
    {
      "code": 20006,
      "message": "Shop 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 shop that wasn't found — 20006.
message string Description of why the resource wasn't found.
422 (Unprocessable Entity) response example
{
  "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.
5XX (Internal Server Error) response example
{
  "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

  1. Don't resend the confirmation or create a new payout based solely on a technical error.
  2. Request the transaction status using the original transaction.
  3. If the transaction is found, keep checking it until you receive a final status.
  4. If status requests keep failing, contact support and provide the transaction.