Перейти к содержанию

Проведение платежа по карте через H2H

H2H (Host-to-Host) — способ приёма оплаты без использования платёжной страницы KVELL. Используйте H2H, если хотите реализовать собственную платёжную страницу.

Метод создаёт одностадийный платёж по реквизитам банковской карты. Перед вызовом метода необходимо создать платёжную сессию; результат платежа определяется позднее по статусу транзакции или колбэку.

Работа с карточными данными

Для использования H2H-интеграции мерчант должен иметь действующий документ, подтверждающий соответствие требованиям PCI DSS.

Не сохраняйте и не логируйте card.pan и card.cvv. Значение card.cvv должно использоваться только для проведения текущего платежа.

Сценарий интеграции

  1. Создайте платёжную сессию с уникальным transaction. Для возврата пользователя на сайт мерчанта после 3-D Secure передайте в сессии redirect_url.
  2. Соберите данные браузера пользователя и передайте реквизиты новой карты в card либо данные привязанной карты в customer_card.
  3. Сформируйте подпись в зависимости от выбранного варианта карты и отправьте запрос на проведение платежа.
  4. Получив 200, перенаправьте браузер пользователя по адресу form_url. На этой странице KVELL выполнит необходимые переходы на страницы банка и 3-D Secure, а затем перенаправит пользователя на redirect_url из сессии. Если redirect_url не был передан, используется адрес платёжной страницы KVELL по умолчанию.
  5. Определяйте результат платежа по статусу транзакции: используйте колбэк или опрашивайте метод статуса с интервалом 10 минут, пока не получите финальный статус.

URL

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

Запрос

Заголовки

Название Тип Обязательно Описание
X-Api-Key string Да Идентификатор магазина.
X-Signature string Да Подпись запроса.

Формирование подписи

Объедините значения без разделителей в указанном порядке, вычислите SHA-256 от строки в кодировке UTF-8 и передайте полученный hex-хеш в нижнем регистре в заголовке X-Signature.

Если используются реквизиты новой карты в объекте card:

SHA256(X-Api-Key + transaction + card.pan + card.expire + card.cvv + card.holder + secret_key)

Если используется привязанная карта в объекте customer_card:

SHA256(X-Api-Key + transaction + customer_card.token + customer_card.cvv + secret_key)

secret_key находится в настройках магазина. Пробелы, переносы строк и другие разделители между значениями добавлять нельзя. Значения должны в точности совпадать с данными в отправляемом JSON.

Тело запроса

Параметр Тип Обязательно Описание
transaction string Да Уникальный номер транзакции на стороне мерчанта, переданный при создании сессии.
card object Условно Реквизиты новой карты. Обязательно, если не передан customer_card.
customer_card object Условно Данные привязанной карты. Обязательно, если не передан card.
customer_key string | null Условно Идентификатор покупателя в системе мерчанта. Обязателен при bind_card: true.
browser_info object Да Данные браузера пользователя. Описание полей приведено ниже.
customer string | null Нет Идентификатор плательщика в системе мерчанта.
bind_card boolean Нет true — привязать карту в KVELL после успешного платежа. По умолчанию false.

Выберите один источник карточных данных

Передавайте ровно один объект: card или customer_card. Формула подписи зависит от выбранного объекта.

Объект card

Параметр Тип Обязательно Описание
pan string Да Номер карты: от 12 до 19 цифр, проходит проверку по алгоритму Луна.
expire string Да Срок действия карты в формате YYYY-MM, например 2028-12.
cvv string Да Трёхзначный код безопасности карты.
holder string Да Имя держателя карты, как указано на карте.

Объект customer_card

Параметр Тип Обязательно Описание
customer_key string Да Идентификатор покупателя, которому принадлежит карта.
token string Да Токен из метода получения списка привязанных карт.
cvv string Да Трёхзначный код безопасности карты.

Объект browser_info

Данные необходимо получить в браузере пользователя непосредственно перед созданием платежа.

Параметр Тип Обязательно Описание
user_agent string Да Содержимое HTTP-заголовка User-Agent. Используйте navigator.userAgent. Максимальная длина — 2048 символов.
accept_header string Нет Содержимое HTTP-заголовка Accept, полученного от браузера пользователя. Максимальная длина — 2048 символов. По умолчанию application/json, text/plain, */*.
color_depth integer Да Глубина цвета экрана в битах на пиксель — значение screen.colorDepth. Допустимые значения: 1, 4, 8, 15, 16, 24, 32, 48; не более 2 цифр.
ip string Да Публичный IPv4- или IPv6-адрес браузера пользователя. IPv4 передаётся четырьмя десятичными группами через ., IPv6 — восемью шестнадцатеричными группами через :.
language string Нет Язык браузера в формате IETF BCP 47, например ru-RU; не более 8 символов. По умолчанию ru-RU.
screen_width integer Да Полная ширина экрана пользователя в пикселях — значение screen.width; не более 6 цифр.
screen_height integer Да Полная высота экрана пользователя в пикселях — значение screen.height; не более 6 цифр.
screen_print string Да Строка с текущим и доступным разрешением экрана, а также глубиной цвета. Формат показан в примере ниже.
tz integer Да Разница между UTC и локальным временем браузера в минутах — значение new Date().getTimezoneOffset(); не более 5 символов с учётом знака. Например, -180 для Москвы.
time_zone string Да Название часового пояса из Intl.DateTimeFormat().resolvedOptions().timeZone, например Europe/Moscow.
java_enabled boolean Да Признак доступности Java в браузере — результат navigator.javaEnabled(): true или false.
device_channel string Да Тип устройства: 01 — мобильное приложение мерчанта, 02 — браузер пользователя, 03 — 3DS Requestor. Для этого H2H-сценария передайте 02.

Формирование browser_info в браузере

Значения ip и accept_header передайте в функцию со своего backend: получите их из входящего запроса пользователя. Остальные параметры можно собрать в браузере непосредственно перед созданием платежа.

function collectBrowserInfo(ip, acceptHeader) {
  const screen = window.screen;

  return {
    user_agent: navigator.userAgent,
    accept_header: acceptHeader || "application/json, text/plain, */*",
    color_depth: screen.colorDepth,
    ip,
    language: navigator.language || "ru-RU",
    screen_width: screen.width,
    screen_height: screen.height,
    screen_print:
      `Current Resolution: ${screen.width}x${screen.height}, ` +
      `Available Resolution: ${screen.availWidth}x${screen.availHeight}, ` +
      `Color Depth: ${screen.colorDepth}`,
    tz: new Date().getTimezoneOffset(),
    time_zone: Intl.DateTimeFormat().resolvedOptions().timeZone,
    java_enabled:
      typeof navigator.javaEnabled === "function"
        ? navigator.javaEnabled()
        : false,
    device_channel: "02"
  };
}

Пример

{
  "transaction": "payment-20260807-0001",
  "browser_info": {
    "user_agent": "Mozilla/5.0",
    "accept_header": "application/json, text/plain, */*",
    "color_depth": 24,
    "ip": "203.0.113.10",
    "language": "ru-RU",
    "screen_width": 1920,
    "screen_height": 1080,
    "screen_print": "Current Resolution: 1920x1080, Available Resolution: 1920x1040, Color Depth: 24",
    "tz": -180,
    "time_zone": "Europe/Moscow",
    "java_enabled": false,
    "device_channel": "02"
  },
  "card": {
    "pan": "5100000000000123",
    "expire": "2034-12",
    "cvv": "123",
    "holder": "VASYA PUPKIN"
  }
}
curl --request POST \
  --url 'https://api.pay.kvell.group/v1/orders/card2account' \
  --header 'Content-Type: application/json' \
  --header 'X-Api-Key: <api-key>' \
  --header 'X-Signature: <signature>' \
  --data '{
    "transaction": "payment-20260807-0001",
    "browser_info": {
      "user_agent": "Mozilla/5.0",
      "accept_header": "application/json, text/plain, */*",
      "color_depth": 24,
      "ip": "203.0.113.10",
      "language": "ru-RU",
      "screen_width": 1920,
      "screen_height": 1080,
      "screen_print": "Current Resolution: 1920x1080, Available Resolution: 1920x1040, Color Depth: 24",
      "tz": -180,
      "time_zone": "Europe/Moscow",
      "java_enabled": false,
      "device_channel": "02"
    },
    "card": {
      "pan": "5100000000000123",
      "expire": "2034-12",
      "cvv": "123",
      "holder": "VASYA PUPKIN"
    }
  }'

Ответ

Выберите HTTP-код, чтобы посмотреть пример, параметры ответа и рекомендуемые действия.

Если HTTP-ответ не получен

Таймаут и разрыв соединения обрабатывайте так же, как ответ 5XX: результат создания платежа неизвестен. Сначала запросите статус по исходному transaction и не создавайте новый платёж, пока результат исходного не установлен.

Пример ответа 200 (OK)
{
  "form_url": "https://api.pay.kvell.group/3ds/form?f=<form-data>"
}

Параметры ответа

Параметр Тип Описание
form_url string URL для продолжения сценария платежа и прохождения 3-D Secure.

Что делать дальше

  1. Перенаправьте браузер пользователя по адресу form_url.
  2. После возврата на redirect_url получите статус транзакции или обработайте колбэк.
Пример ответа 400 (Bad Request)
{
  "errors": [
    {
      "code": 20007,
      "message": "Транзакция совершалась прежде"
    }
  ]
}

Параметры ответа

Параметр Тип Описание
errors array Список ошибок. Коды и рекомендации по обработке приведены в разделе «Ошибки HTTP-ответов».
errors[].code integer Код ошибки. В примере — 20007.
errors[].message string Описание причины отклонения запроса.

Что делать дальше

  1. При 20007 не создавайте дубликат — запросите статус исходного transaction.
  2. При 20004 повторно создайте сессию с тем же transaction, затем повторите запрос платежа.
  3. Для остальных кодов выполните рекомендацию из справочника HTTP-ошибок.
Пример ответа 403 (Forbidden)
{
  "errors": [
    {
      "code": 20037,
      "message": "Доступ запрещен"
    }
  ]
}

Параметры ответа

Параметр Тип Описание
errors array Список ошибок. Коды и рекомендации по обработке приведены в разделе «Ошибки HTTP-ответов».
errors[].code integer Код ошибки. Для запрета доступа — 20037.
errors[].message string Описание причины запрета доступа.

Что делать дальше

Проверьте статус магазина и обратитесь к менеджеру KVELL. Повторяйте запрос только после восстановления доступа.

Пример ответа 404 (Not Found)
{
  "errors": [
    {
      "code": 20006,
      "message": "Магазин не найден"
    }
  ]
}

Параметры ответа

Параметр Тип Описание
errors array Список ошибок. Коды и рекомендации по обработке приведены в разделе «Ошибки HTTP-ответов».
errors[].code integer Код ошибки. В примере — 20006.
errors[].message string Описание причины, по которой ресурс не найден.

Что делать дальше

Проверьте X-Api-Key и контур Stage/Production. Не повторяйте запрос с теми же данными, пока не исправите причину.

Пример ответа 422 (Unprocessable Entity)
{
  "errors": [
    {
      "code": 20098,
      "message": "transaction: Field required"
    }
  ]
}

Параметры ответа

Параметр Тип Описание
errors array Список ошибок валидации. Коды и рекомендации по обработке приведены в разделе «Ошибки HTTP-ответов».
errors[].code integer Код ошибки валидации. Для ошибки поля — 20098.
errors[].message string Название поля и причина ошибки валидации.
Пример ответа 5XX (Internal Server Error)
{
  "errors": [
    {
      "code": 20000,
      "message": "Неизвестная ошибка"
    }
  ]
}

Параметры ответа

Параметр Тип Описание
errors array Список ошибок. Коды и рекомендации по обработке приведены в разделе «Ошибки HTTP-ответов».
errors[].code integer Код ошибки. Для неизвестной ошибки — 20000.
errors[].message string Описание технической ошибки.

5XX, таймаут и разрыв соединения

Во всех этих случаях результат запроса считается неопределённым: платёж мог быть создан, даже если клиент не получил ответ. Оставьте операцию в своей системе в состоянии «обрабатывается» до получения подтверждённого результата от KVELL.

Единый алгоритм обработки

  1. Не создавайте новый платёж и не меняйте transaction.
  2. Запросите статус транзакции по исходному transaction.
  3. Если транзакция найдена, проверяйте её до финального статуса или дождитесь колбэка.
  4. Если запросы статуса продолжают завершаться технической ошибкой, обратитесь в поддержку и передайте transaction.

Привязка карты при платеже

Чтобы привязать новую карту к покупателю в KVELL, добавьте в запрос bind_card: true и передайте customer_key.

{
  "bind_card": true,
  "customer_key": "customer-42"
}

Оплата привязанной картой

Если карта была привязана ранее, передайте customer_card вместо card и сформируйте подпись по формуле для привязанной карты.

{
  "transaction": "payment-20260807-0002",
  "browser_info": {
    "user_agent": "Mozilla/5.0",
    "accept_header": "application/json, text/plain, */*",
    "color_depth": 24,
    "ip": "203.0.113.10",
    "language": "ru-RU",
    "screen_width": 1920,
    "screen_height": 1080,
    "screen_print": "Current Resolution: 1920x1080, Available Resolution: 1920x1040, Color Depth: 24",
    "tz": -180,
    "time_zone": "Europe/Moscow",
    "java_enabled": false,
    "device_channel": "02"
  },
  "customer_card": {
    "customer_key": "customer-42",
    "token": "<card-token>",
    "cvv": "123"
  }
}

Карта станет доступна в методе получения списка карт после успешного завершения платежа со статусом completed. Привязка действует в рамках магазина из X-Api-Key.