Payment Docs
Рекуррентные платежи

Вебхуки связок

Подписанные уведомления о смене статуса рекуррентных связок

О каждой смене статуса связки мы отправляем подписанный POST-запрос. Списания — это заказы: их результат приходит обычными вебхуками заказов с X-Type: ORDER_UPDATE.

Адрес отправки уведомлений

Адрес определяется в таком порядке:

  1. callbackUrl связки (передаётся в POST /v1/recurring/bindings);
  2. callbackUrl заказа первого платежа (для связки, сохранённой с платежом);
  3. callbackUrl из настроек мерчанта;
  4. если ничего не задано, уведомления по связке не отправляются.

Условия отправки уведомлений

Уведомление формируется при смене статуса связки: ACTIVE после подтверждения плательщиком, FAILED, SUSPENDED, DELETED. Начальный статус PENDING не отправляется: он возвращается при создании связки.

Для связки, сохранённой с первым платежом, уведомление ACTIVE обычно приходит прямо перед уведомлением заказа со статусом COMPLETED.

Дубли исключаются по сочетанию адреса, ID связки и статуса среди неотправленных уведомлений.

Формат уведомления

POST {callbackUrl}
Content-Type: application/json
X-Type: RECURRING_BINDING_UPDATE
X-Signature: HMAC-SHA512(тело запроса, API-токен) в hex

Тело

{
  "id": "0199a1b2-c3d4-7e5f-8a9b-0c1d2e3f4a5b",
  "status": "ACTIVE",
  "isTest": false,
  "externalId": "sub-42",
  "externalUserId": "user_987",
  "merchantId": "0199a1b2-c3d4-7e5f-8a9b-0c1d2e3f4a5e",
  "purpose": "Ежемесячная подписка",
  "initialOrderId": "0199a1b2-c3d4-7e5f-8a9b-0c1d2e3f4a5c",
  "bankName": "Сбербанк",
  "bankLogoUrl": null,
  "createdAt": "2026-10-21T12:34:56.000Z",
  "updatedAt": "2026-10-21T12:36:10.512Z",
  "activatedAt": "2026-10-21T12:36:10.512Z",
  "closedAt": null
}
ПолеТипОписание
idstring (UUID)ID связки
statusstringТекущий статус, см. Статусы связки
isTestbooleanТестовая связка
externalIdstring / nullID связки в вашей системе
externalUserIdstringID плательщика в вашей системе
merchantIdstring (UUID)Ваш ID мерчанта
purposestring / nullОписание подписки
initialOrderIdstring / nullЗаказ, оплата которого создала связку
bankNamestring / nullБанк плательщика
bankLogoUrlstring / nullЛоготип банка плательщика
createdAtstringВремя создания
updatedAtstringВремя последнего изменения
activatedAtstring / nullКогда связка впервые стала ACTIVE
closedAtstring / nullКогда связка стала DELETED или FAILED

Проверка подписи

Каждое уведомление содержит заголовок X-Signature: HMAC-SHA512 от сырого тела запроса в hex, ключ — ваш API-токен. Та же схема используется для вебхуков платежей, выплат и возвратов.

import crypto from "crypto";

// Ваш API-токен используется как секрет для HMAC
const apiToken = process.env.API_TOKEN;

app.post("/webhooks/payments", (req, res) => {
  const signature = req.headers["x-signature"];
  const body = JSON.stringify(req.body);

  // Считаем HMAC-SHA512 от тела запроса и сравниваем в HEX
  const expected = crypto.createHmac("sha512", apiToken).update(body).digest("hex");

  if (expected !== signature) {
    return res.status(403).send("Invalid signature");
  }

  // Подпись верна — обрабатываем уведомление идемпотентно
  const data = req.body;
  if (data.status === "COMPLETED") {
    console.log(`Заказ ${data.externalId} оплачен`);
  }

  res.status(200).send("OK");
});

Если один адрес получает уведомления разных типов, различайте их по заголовку X-Type: ORDER_UPDATE, PAYOUT_UPDATE, REFUND_UPDATE или RECURRING_BINDING_UPDATE.

Политика повторных отправок

ПараметрЗначение
Попыткидо 30
Интервал30 с × 2^n, не больше 30 минут
Критерий успехаHTTP-статус 200–399

Также действует circuit breaker: адрес, который стабильно отвечает ошибками, временно исключается из доставки.

Рекомендации по работе с webhook-уведомлениями

  • Всегда отвечайте кодом HTTP 200, чтобы подтвердить получение. Если ваш сервер не отвечает, мы повторяем отправку уведомления.
  • Проверяйте заголовок X-Signature перед обработкой тела запроса.
  • Обрабатывайте уведомления идемпотентно: одно и то же уведомление может быть доставлено несколько раз.
  • Сопоставляйте уведомление с вашими записями по externalId, а не по сумме.
  • Обрабатывайте все возможные значения статусов, включая неуспешные.

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

На этой странице