Recurring Payment by a Card from Another Bank
The method charges the customer's card without their involvement when the card was set up for recurring payments with another acquirer.
Enabling the method
The method is available only to shops for which it is enabled in KVELL. Contact your manager to enable it.
Handling card data
The method accepts the full card number. The merchant must have a valid document confirming compliance with
PCI DSS requirements. Do not log card.pan and store it only in secure storage.
Integration flow
- Obtain from the previous acquirer the identifier of the customer's initial payment in which the card was set up for recurring charges, and store it together with the card details.
- When a charge is due, build the signature and send the request with a new unique
transaction, passing the acquirer's initial payment identifier ininitial_network_transaction_id. - Determine the result from the
statusfield of the200response:completed— the charge succeeded,canceled— it was declined, and the reason is inerror_code. - If the status in the response is not final, request the transaction status by
transactionuntil you receive a final one, or wait for the callback — it is sent when the status becomes final.
URL
Request
Headers
| Name | Type | Required | Description |
|---|---|---|---|
X-Api-Key |
string | Yes | Shop identifier. |
X-Signature |
string | Yes | Request signature. |
Building the signature
Concatenate the values without separators in the order shown, compute SHA-256 of the UTF-8 string and pass the
resulting lowercase hex hash in the X-Signature header:
SHA256(X-Api-Key + transaction + amount + card.pan + card.expire + initial_network_transaction_id + secret_key)
secret_key is in the shop settings. Do not add spaces, line breaks or other separators between the values. The
values must exactly match the data in the JSON being sent.
Request body
| Parameter | Type | Required | Description |
|---|---|---|---|
transaction |
string | Yes | Unique transaction number on the merchant's side. |
amount |
integer | Yes | Charge amount in kopecks, greater than zero. |
description |
string | Yes | Payment description, up to 99 characters. |
card |
object | Yes | Card details. The fields are described below. |
initial_network_transaction_id |
string | Yes | Initial payment identifier from the previous acquirer. |
fiscal_data |
object | null | No | Data for receipt fiscalization under 54-FZ. |
extra_data |
object | null | No | Additional merchant parameters. |
card object
| Parameter | Type | Required | Description |
|---|---|---|---|
pan |
string | Yes | Card number: 12 to 19 digits, passes the Luhn check. |
expire |
string | Yes | Card expiry date in YYYY-MM format, for example 2028-12. |
holder |
string | null | No | Cardholder name as shown on the card. |
Example
curl --request POST \
--url 'https://api.pay.kvell.group/v1/orders/rebill-external-card' \
--header 'Content-Type: application/json' \
--header 'X-Api-Key: <api-key>' \
--header 'X-Signature: <signature>' \
--data '{
"transaction": "rebill-20261031-0001",
"amount": 15000,
"description": "Payment under contract 42",
"card": {
"pan": "2201382000000021",
"expire": "2028-12",
"holder": "IVAN IVANOV"
},
"initial_network_transaction_id": "483012345678901",
"extra_data": {
"contract": "42"
}
}'
Response
Select 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 drop the same way as a 5XX response: the result of the charge is unknown. First
request the status for the original transaction and do not send a new charge until the result of the original
one is determined.
{
"id": "b13e1610-f26a-4c49-84e8-0edf1650a026",
"status": "completed",
"transaction": "rebill-20261031-0001",
"amount": 15000,
"commission": 0,
"inner_commission": 0,
"description": "Payment under contract 42",
"success_url": null,
"fail_url": null,
"redirect_url": null,
"extra_data": {
"contract": "42"
},
"fiscal_data": null,
"additional_data": {},
"error_code": null,
"error_message": null,
"created_at": "2026-10-31T12:55:00.951753+00:00",
"refund_amount": 0,
"reverse_amount": 0,
"confirm_amount": 0,
"instrument": "card",
"ecommerce_type": "payment"
}
HTTP code 200 means the request was accepted and processed. The charge result is determined by the status
field, not by the HTTP code: a bank decline is also returned with code 200 and status canceled.
Response parameters
| Parameter | Type | Description |
|---|---|---|
id |
string | Payment identifier in KVELL. |
status |
string | Payment status. The values are listed in Transaction statuses. |
transaction |
string | Transaction number from the request. |
amount |
integer | Amount in kopecks. |
commission |
integer | Commission in kopecks. |
inner_commission |
integer | Internal commission in kopecks. |
description |
string | null | Payment description from the request. |
success_url |
string | null | null for this method. |
fail_url |
string | null | null for this method. |
redirect_url |
string | null | null for this method. |
extra_data |
object | Additional parameters from the request. |
fiscal_data |
object | null | Fiscalization data from the request. |
additional_data |
object | null | Additional payment data. |
error_code |
string | null | Decline reason when the status is canceled. The values are listed in Transaction error codes. |
error_message |
string | null | Text description of the decline reason. |
created_at |
string | Payment creation date and time in ISO 8601 format. |
refund_amount |
integer | null | Refunded amount in kopecks. |
reverse_amount |
integer | null | Reversed amount in kopecks. |
confirm_amount |
integer | null | Confirmed amount in kopecks. |
instrument |
string | null | Payment instrument — card. |
ecommerce_type |
string | null | Operation type — payment. |
What to do next
- On
completed, mark the charge as successful. - On
canceled, checkerror_code. Send a repeat charge with a newtransaction. - On
neworprocessing, request the transaction status bytransactionuntil the status is final, or wait for the callback.
{
"errors": [
{
"code": 20007,
"message": "Транзакция совершалась прежде"
}
]
}
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 — 20007. |
errors[].message |
string | 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. |
errors[].code |
integer | Error code. |
errors[].message |
string | Reason access was denied. |
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. |
errors[].message |
string | Reason the resource was not found. |
{
"errors": [
{
"code": 20098,
"message": "initial_network_transaction_id: 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 | Validation error code. |
errors[].message |
string | Field name and validation error reason. |
{
"errors": [
{
"code": 20000,
"message": "Неизвестная ошибка"
}
]
}
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 drop
In all these cases the result of the request is undetermined: the charge may have gone through even if the client did not receive a response. Keep the operation in your system in the "processing" state until you get a confirmed result from KVELL.
Handling algorithm
- Do not create a new payment and do not change
transaction. - Request the transaction status for the original
transaction. - If status requests keep failing with a technical error, contact support and provide
transaction.