Публичный ключ для криптограммы
Возвращает актуальный публичный RSA-ключ KVELL. Этим ключом на стороне мерчанта шифруются реквизиты банковской карты перед отправкой в KVELL: вместо открытых реквизитов передаётся криптограмма.
Сценарий интеграции
- Запросите публичный ключ этим методом.
- Сохраните
public_keyиkey_idв своём кэше до моментаrefresh_after. - Зашифруйте реквизиты карты полученным ключом и получите криптограмму.
- Передайте криптограмму в API-метод, который её принимает.
- Перед следующим использованием ключа проверьте
refresh_afterи при необходимости запросите ключ заново.
URL
Запрос
Заголовки
| Название | Тип | Обязательно | Описание |
|---|---|---|---|
X-Api-Key |
string | Да | Идентификатор магазина. |
Пример
curl --request GET \
--url 'https://api.pay.stage.kvell.group/v1/cryptogram/public-key' \
--header 'X-Api-Key: 00000000-0000-4000-8000-000000000000'
Ответ
Выберите HTTP-код, чтобы посмотреть пример, параметры ответа и рекомендуемые действия.
{
"public_key": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu6tJntpB49kze14gfIkQ\nAQIDAQAB\n-----END PUBLIC KEY-----\n",
"key_id": "068eb60b259651c4",
"refresh_after": "2026-08-20T10:20:48.650203Z"
}
Параметры ответа
| Параметр | Тип | Описание |
|---|---|---|
public_key |
string | Публичный ключ RSA-2048 в формате PEM. |
key_id |
string | Идентификатор ключа. Вычисляется как SHA-256 от DER-представления SubjectPublicKeyInfo, усечённая до первых 16 символов, поэтому его можно пересчитать самостоятельно из public_key. |
refresh_after |
string | Момент в UTC по ISO 8601, до которого возвращённый ключ гарантированно актуален. Подробнее — в разделе «Кэширование и ротация ключа». |
Что делать дальше
- Сохраните
public_keyиkey_idв кэше доrefresh_after. - Используйте ключ для формирования криптограммы.
Параметры ответа
| Параметр | Тип | Описание |
|---|---|---|
errors |
array | Список ошибок. Коды и рекомендации приведены в разделе «Ошибки HTTP-ответов». |
errors[].code |
integer | Код ошибки. В примере — 20037. |
errors[].message |
string | Описание причины запрета доступа. |
Параметры ответа
| Параметр | Тип | Описание |
|---|---|---|
errors |
array | Список ошибок. Коды и рекомендации приведены в разделе «Ошибки HTTP-ответов». |
errors[].code |
integer | Код ошибки. В примере — 20006. |
errors[].message |
string | Описание ресурса, который не найден. |
{
"errors": [
{
"code": 20098,
"message": "x-api-key: Field required"
}
]
}
Параметры ответа
| Параметр | Тип | Описание |
|---|---|---|
errors |
array | Список ошибок валидации. Коды и рекомендации приведены в разделе «Ошибки HTTP-ответов». |
errors[].code |
integer | Код ошибки. Для ошибки поля — 20098. |
errors[].message |
string | Поле и причина ошибки валидации. |
{
"errors": [
{
"code": 20043,
"message": "Публичный ключ криптограммы временно недоступен"
}
]
}
Параметры ответа
| Параметр | Тип | Описание |
|---|---|---|
errors |
array | Список ошибок. Коды и рекомендации приведены в разделе «Ошибки HTTP-ответов». |
errors[].code |
integer | Код технической ошибки. |
errors[].message |
string | Описание технической ошибки. |
Что делать дальше
- Безопасно повторите тот же GET-запрос с тем же
X-Api-Key. - При повторяющейся ошибке обратитесь в поддержку KVELL и передайте URL, время запроса, HTTP-код,
codeиmessage.
Как формируется криптограмма
Работа с карточными данными
Реквизиты карты шифруются на стороне мерчанта и в KVELL передаются только в виде криптограммы. Не сохраняйте и не логируйте номер карты и CVV, включая промежуточные значения до шифрования.
Криптограмма формируется в два шага.
-
Соберите строку с реквизитами карты. Поля разделяются двумя двоеточиями, порядок фиксированный:
Поле Обязательно Описание panДа Номер карты. cvvНет Проверочный код карты. holderНет Имя держателя карты. exp_dateНет Срок действия карты, ровно 5 символов в формате ГГ/ММ, например26/01.Необязательные поля можно опустить, обрезав строку справа: значения
4111111111111111::123и4111111111111111также корректны. Пропустить поле в середине нельзя — пустое значение будет разобрано как пустая строка, а не как отсутствующее. -
Зашифруйте строку публичным ключом и закодируйте результат в Base64.
Параметр Значение Алгоритм RSA-OAEP Хеш-функция SHA-256 Функция формирования маски MGF1 с SHA-256 Метка (label) Не используется Кодирование результата Base64 со стандартным алфавитом и выравниванием
При длине ключа 2048 бит и OAEP с SHA-256 максимальная длина исходной строки — 190 байт. Полные реквизиты карты в этот предел укладываются.
Примеры
В примерах используется тестовая карта 4111111111111111 со сроком действия 2034-12, который
в криптограмме записывается как 34/12.
Требуется пакет: pip install cryptography.
import base64
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives.serialization import load_pem_public_key
# значение поля public_key из ответа метода
public_key_pem = '-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----\n'
public_key = load_pem_public_key(public_key_pem.encode('utf-8'))
payload = '4111111111111111::123::TEST HOLDER::34/12'
cryptogram = base64.b64encode(
public_key.encrypt(
payload.encode('utf-8'),
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None,
),
)
).decode('ascii')
print(cryptogram)
Используется встроенный модуль node:crypto.
const crypto = require('node:crypto');
// значение поля public_key из ответа метода
const publicKeyPem = '-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----\n';
const payload = '4111111111111111::123::TEST HOLDER::34/12';
const cryptogram = crypto.publicEncrypt(
{
key: publicKeyPem,
padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
oaepHash: 'sha256',
},
Buffer.from(payload, 'utf8'),
).toString('base64');
console.log(cryptogram);
# 1. Сохраните публичный ключ в файл
curl -s --request GET \
--url 'https://api.pay.stage.kvell.group/v1/cryptogram/public-key' \
--header 'X-Api-Key: 00000000-0000-4000-8000-000000000000' \
| jq -r '.public_key' > public_key.pem
# 2. Зашифруйте реквизиты карты и закодируйте результат в Base64
printf '%s' '4111111111111111::123::TEST HOLDER::34/12' \
| openssl pkeyutl -encrypt -pubin -inkey public_key.pem \
-pkeyopt rsa_padding_mode:oaep \
-pkeyopt rsa_oaep_md:sha256 \
-pkeyopt rsa_mgf1_md:sha256 \
| openssl base64 -A
Кэширование и ротация ключа
Ключ можно кэшировать. Поле refresh_after указывает момент, до которого возвращённое значение гарантированно
актуально; после его наступления запросите ключ заново. Запрашивать ключ перед каждой операцией не требуется.
Ротация ключа не требует синхронного перехода: криптограммы, зашифрованные ключом, полученным до ротации, ещё
некоторое время принимаются. Чтобы не зависеть от этого запаса, соблюдайте refresh_after.
Значение key_id меняется вместе с ключом, поэтому по нему удобно определить, что ключ обновился, и указать его при
обращении в поддержку.