Получение карты по транзакции
Возвращает привязанную карту покупателя, которой была проведена операция, по идентификатору transaction
в системе мерчанта. В ответе — токен карты для повторных оплат, маска номера, данные банка-эмитента и, если для
магазина задан публичный ключ, зашифрованный хеш номера карты.
Сценарий интеграции
- Проведите операцию с привязкой карты: передайте
customer_keyиbind_card: true, например в платеже по карте через H2H или платеже с предавторизацией. - Сохраните
transactionиcustomer_keyэтой операции. - Сформируйте подпись из
X-Api-Key,transaction,customer_keyиsecret_key. - Отправьте запрос с тем же
X-Api-Key, с которым создавалась операция. - Сохраните
tokenкарты, чтобы использовать его для оплаты привязанной картой.
URL
Запрос
Path-параметры
| Параметр | Тип | Обязательно | Описание |
|---|---|---|---|
customer_key |
string | Да | Идентификатор покупателя в системе мерчанта. |
transaction |
string | Да | Идентификатор операции в системе мерчанта. |
Заголовки
| Название | Тип | Обязательно | Описание |
|---|---|---|---|
X-Api-Key |
string | Да | Идентификатор магазина. |
X-Signature |
string | Да | Подпись запроса. |
Формирование подписи
Объедините X-Api-Key, transaction, customer_key и secret_key без разделителей, вычислите SHA-256
от полученной строки в кодировке UTF-8 и передайте хеш в нижнем регистре в заголовке X-Signature.
secret_key находится в настройках магазина.
Пример
Ответ
Выберите HTTP-код, чтобы посмотреть пример, параметры ответа и рекомендуемые действия.
{
"customer_id": 25,
"token": "4VNSbS7nF410G8WLEhUUUnflH2UKvWlHxIzN3Jr9JJs",
"pan_mask": "411111******1111",
"holder": "IVAN IVANOV",
"expire": "2034-12",
"created_at": "2026-10-02T07:52:29.720321Z",
"pan_hash_encrypted": "EPNS42BPO6yazHvd6BKd...ObPg6EKv7mYKUy7zc8s=",
"bank_id": "100000000004",
"bank_name": "Tinkoff Bank",
"bank_url": "tinkoff.ru"
}
Параметры ответа
| Параметр | Тип | Описание |
|---|---|---|
customer_id |
integer | Идентификатор покупателя в KVELL. |
token |
string | Токен привязанной карты. Используется для оплаты привязанной картой. |
pan_mask |
string | Маска номера карты. |
holder |
string | null | Имя держателя карты. |
expire |
string | null | Срок действия карты в формате YYYY-MM. |
created_at |
string | Дата и время привязки карты в формате ISO 8601. |
pan_hash_encrypted |
string | null | Хеш номера карты, зашифрованный публичным ключом магазина, в Base64. Расшифровка описана в разделе «Расшифровка хеша номера карты». |
bank_id |
string | null | Идентификатор банка-эмитента карты. |
bank_name |
string | null | Название банка-эмитента карты. |
bank_url |
string | null | Домен сайта банка-эмитента карты. |
Что означает ответ
Операция найдена, и карта, которой она проведена, привязана к покупателю.
Поля bank_id, bank_name и bank_url определяются по BIN карты и возвращаются со значением null,
если банк определить не удалось. Если при шифровании хеша номера карты произошла ошибка,
pan_hash_encrypted возвращается со значением null, а остальные поля ответа заполняются.
Что делать дальше
- Сохраните
tokenи используйте его для оплаты привязанной картой. - Если нужен
pan_hash_encrypted, расшифруйте его приватным ключом магазина.
Параметры ответа
| Параметр | Тип | Описание |
|---|---|---|
errors |
array | Список ошибок. Коды и рекомендации по обработке приведены в разделе «Ошибки HTTP-ответов». |
errors[].code |
integer | Код ошибки. В примере — 20002. |
errors[].message |
string | Описание причины отклонения запроса. |
Параметры ответа
| Параметр | Тип | Описание |
|---|---|---|
errors |
array | Список ошибок. Коды и рекомендации по обработке приведены в разделе «Ошибки HTTP-ответов». |
errors[].code |
integer | Код ошибки. В примере — 20037. |
errors[].message |
string | Описание причины запрета доступа. |
Параметры ответа
| Параметр | Тип | Описание |
|---|---|---|
errors |
array | Список ошибок. Коды и рекомендации по обработке приведены в разделе «Ошибки HTTP-ответов». |
errors[].code |
integer | Код ошибки. В примере — 20009. |
errors[].message |
string | Описание ресурса, который не найден. |
{
"errors": [
{
"code": 20017,
"message": "customer_key не задан"
}
]
}
Параметры ответа
| Параметр | Тип | Описание |
|---|---|---|
errors |
array | Список ошибок. Коды и рекомендации по обработке приведены в разделе «Ошибки HTTP-ответов». |
errors[].code |
integer | Код ошибки. В примере — 20017. |
errors[].message |
string | Причина ошибки. |
{
"errors": [
{
"code": 20000,
"message": "Неизвестная ошибка"
}
]
}
Параметры ответа
| Параметр | Тип | Описание |
|---|---|---|
errors |
array | Список ошибок. Коды и рекомендации по обработке приведены в разделе «Ошибки HTTP-ответов». |
errors[].code |
integer | Код ошибки. Для неизвестной ошибки — 20000. |
errors[].message |
string | Описание технической ошибки. |
Что делать дальше
- Безопасно повторите тот же
GET-запрос с исходнымиcustomer_keyиtransaction. - При повторяющейся ошибке обратитесь в поддержку KVELL и передайте URL, время запроса, HTTP-код,
codeиmessage.
Расшифровка хеша номера карты
Поле pan_hash_encrypted позволяет сопоставить карту с картами в вашей системе, не получая номер карты.
KVELL вычисляет SHA-256 от номера карты, записывает результат строкой в шестнадцатеричном формате в нижнем
регистре и шифрует её публичным ключом магазина.
| Параметр | Значение |
|---|---|
| Алгоритм | RSA-OAEP |
| Хеш-функция | SHA-256 |
| Функция формирования маски | MGF1 с SHA-256 |
| Метка (label) | Не используется |
| Кодирование результата | Base64 |
Расшифруйте значение приватным ключом магазина. Результат — строка из 64 шестнадцатеричных символов, которую
можно сравнить с sha256(pan), вычисленным на вашей стороне.
Работа с приватным ключом
Храните приватный ключ только на своём сервере. Не передавайте его в KVELL и не используйте в клиентском коде.
Требуется пакет: pip install cryptography.
import base64
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import padding
with open('private_key.pem', 'rb') as key_file:
private_key = serialization.load_pem_private_key(key_file.read(), password=None)
# значение поля pan_hash_encrypted из ответа метода
encrypted_base64 = 'EPNS42BPO6yazHvd6BKd...ObPg6EKv7mYKUy7zc8s='
pan_hash = private_key.decrypt(
base64.b64decode(encrypted_base64),
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None,
),
).decode('ascii')
print(pan_hash)
Используется встроенный модуль node:crypto.
const crypto = require('node:crypto');
const fs = require('node:fs');
const privateKeyPem = fs.readFileSync('private_key.pem', 'utf8');
// значение поля pan_hash_encrypted из ответа метода
const encryptedBase64 = 'EPNS42BPO6yazHvd6BKd...ObPg6EKv7mYKUy7zc8s=';
const panHash = crypto.privateDecrypt(
{
key: privateKeyPem,
padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
oaepHash: 'sha256',
},
Buffer.from(encryptedBase64, 'base64'),
).toString('ascii');
console.log(panHash);