Вебхуки: как xpayment уведомляет ваш сервер о платежах

Что такое webhooks xpayment, когда они срабатывают, как их настроить и как обрабатывать события платежей и возвратов.

Что такое вебхук?

Вебхук — это HTTP-запрос, который xpayment отправляет на ваш сервер, когда с платежом что-то происходит. Например, когда покупатель оплатил счёт или отклонил его.

Представьте разницу между двумя подходами:

Вебхук — это push-уведомление для серверов.


Какую роль играет вебхук в платёжном потоке?

Вебхук — это завершающее звено в обоих платёжных сценариях xpayment:

Прямой платёж (POST /v1/payments)

Ваш сервер → xpayment → Kaspi (push на телефон покупателя)
                                     ↓ покупатель оплачивает
Ваш сервер ← xpayment (webhook) ← Kaspi (меняет статус)

Шаг 7 из 8 в потоке прямого платежа — именно здесь срабатывает вебхук. Без него ваш сервер не знает, когда выполнять заказ.

Платёжная ссылка (POST /v1/payments/link)

Ваш сервер → создаёт ссылку → покупатель открывает в Kaspi
                                     ↓ покупатель оплачивает
Ваш сервер ← xpayment (webhook) ← Kaspi (меняет статус)

Шаг 6 из 6 — без вебхука вы не узнаете, что покупатель перешёл по ссылке и оплатил.


Зачем вебхук, если есть GET /payments/{id}?

Polling (GET) Webhook (POST)
Задержка До 15 сек (интервал вашего поллера) Секунды после оплаты
Нагрузка Постоянные лишние запросы Только при событии
Масштаб Сложно при тысячах платежей Не зависит от объёма
Пропуск событий Можно пропустить при сбое Повтор при ошибке

Polling подходит как резервный механизм. Вебхук — как основной.

xpayment использует свой внутренний поллер (каждые 15 сек) для опроса Kaspi — и именно тогда срабатывает доставка вебхука на ваш сервер.

Как добавить вебхук в xpayment

Что нужно перед настройкой


Шаг 1 — Откройте раздел Вебхуки

В боковом меню личного кабинета нажмите «Вебхуки» (или перейдите по адресу /app/webhooks). Вы увидите список существующих подписок (пустой, если вебхуков ещё нет).


Шаг 2 — Создайте новый вебхук

Нажмите кнопку «Создать вебхук». Откроется модальное окно с двумя вкладками:

Вариант А — Быстрый запуск (рекомендуется)

Если вы используете одну из платформ-партнёров xpayment (например, tec.delivery) — выберите её карточку. URL и настройки заполнятся автоматически.

Вариант Б — Ввести вручную

Заполните поля самостоятельно:

Поле Описание
URL Полный HTTPS-адрес вашего эндпоинта. Например: https://api.myshop.kz/webhooks/xpayment
Описание Необязательное название — для вашего удобства
Секрет Случайная строка для подписи запросов (необязательно, но рекомендуется)

Шаг 3 — Выберите события

Отметьте галочками, о каких событиях вы хотите получать уведомления. Рекомендуем выбрать все 5 событий — так ваш сервер всегда будет в курсе любых изменений:


Шаг 4 — Сохраните

Нажмите «Создать». Вебхук появится в списке со статусом «Активен». С этого момента xpayment будет отправлять POST-запрос на ваш URL при каждом выбранном событии.


Совет: Для тестирования можно использовать сервисы вроде webhook.site — они дают временный публичный URL и показывают входящие запросы в реальном времени.

На диаграмме ниже показан интерфейс создания вебхука в xpayment:

Типы событий

xpayment поддерживает 6 типов событий — по одному для каждого возможного исхода платежа или возврата.


payment.completed

Когда: Покупатель нажал «Оплатить» в приложении Kaspi и транзакция прошла успешно.

Что делать на вашем сервере:

Это главное событие — именно его ждёт большинство интеграций.


payment.expired

Когда: Покупатель не оплатил QR-код до истечения его срока действия (обычно 15 минут).

Что делать:


payment.cancelled

Когда: Платёж был отменён — либо вашим сервером (через POST /v1/payments/{id}/cancel), либо покупатель нажал «Отклонить счёт» в Kaspi.

Что делать:


payment.failed

Когда: Kaspi отклонил платёж — недостаточно средств, неверный номер телефона, технический сбой на стороне Kaspi.

Что делать:


payment.refunded

Когда: Возврат по завершённому платежу был успешно выполнен через POST /v1/refunds.

Что делать:


payment.refund_failed

Когда: Попытка возврата завершилась ошибкой — например, Kaspi не смог провести обратную транзакцию.

Что делать:


Таблица событий

Событие Триггер Действие
payment.completed Покупатель оплатил Выполнить заказ
payment.expired QR-код истёк Освободить резерв, предложить новый платёж
payment.cancelled Отменён вами или покупателем Освободить резерв
payment.failed Kaspi отклонил платёж Попросить повторить
payment.refunded Возврат прошёл Обновить статус заказа
payment.refund_failed Возврат не прошёл Ручная проверка

На диаграмме ниже показан путь от смены статуса в Kaspi до доставки вебхука на ваш сервер:

Формат payload

Когда событие срабатывает, xpayment отправляет POST-запрос на ваш URL с таким телом:

{
  "event": "payment.completed",
  "event_version": "1",
  "delivery_id": "c09a3647-7822-4899-8401-3857cbd5bf68",
  "attempt_number": 1,
  "source": "xpayment",
  "payment_id": "65cd0d84-5f66-4763-94d2-1b8e1ba68347",
  "merchant_order_id": "order-5512",
  "created_at": "2026-04-17T10:32:00+05:00"
}

Поля:

Поле Тип Описание
event string Тип события, например payment.completed
event_version string Версия схемы payload (сейчас 1)
delivery_id string Уникальный ID доставки — используйте для идемпотентности
attempt_number int Номер попытки доставки, начинается с 1 и растёт при повторах
source string Всегда xpayment
payment_id string ID платежа, к которому относится событие
merchant_order_id string Ваш ID заказа (отсутствует, если вы его не задавали)
created_at string Время события (ISO 8601)

Заголовки запроса

xpayment отправляет следующие HTTP-заголовки:

POST /webhooks/xpayment HTTP/1.1
Content-Type: application/json
User-Agent: Go-http-client/2.0
X-xPayment-Signature: aeafc0dcd86de4d4d376f525be2b1175520c2818c93938ec8d069957c63a373b

X-xPayment-Signature — это HMAC-SHA256 от тела запроса (см. раздел Безопасность ниже).


Повтор при ошибке

Если ваш эндпоинт вернул не-2xx статус (например, 500 Internal Server Error или 503 Service Unavailable), xpayment пометит доставку как неудачную и попытается повторить её позже (всего до 3 попыток; attempt_number увеличивается каждый раз).

Рекомендации:


Идемпотентность

Иногда одно и то же событие может быть доставлено дважды — при повторе после тайм-аута или сбоя сети. Защита:

  1. Проверяйте delivery_id — сохраняйте полученные delivery_id. Если такой delivery_id уже обработан — пропустите.
  2. Проверяйте payment_id — ID платежа тоже уникален. Если платёж со статусом COMPLETED уже записан — не выполняйте заказ повторно.
// Пример проверки идемпотентности
const deliveryId = payload.delivery_id
if (await alreadyProcessed(deliveryId)) {
  return res.status(200).json({ ok: true }) // acknowledge without processing
}

await markAsProcessed(deliveryId)
await fulfillOrder(payload.merchant_order_id)

Безопасность

Каждая доставка вебхука подписывается. xpayment вычисляет HMAC-SHA256 от точного «сырого» тела запроса с ключом — вашим секретом подписки (secret) — и отправляет результат в виде hex в нижнем регистре в заголовке X-xPayment-Signature (чистый hex — без префикса sha256=).

Чтобы доверять входящему вебхуку:


Смотрите также