Вебхуки

Вебхук — HTTP POST с JSON на адрес вашего проекта при смене статуса счёта. Это основной способ узнать об оплате: не полагайтесь на возврат покупателя на successUrl.

API v1 · обновлено 2026-09-12

Настройка

Адрес приёма задаётся в настройках проекта — поле webhook_url. Требования: только HTTPS, публично доступный хост (не localhost, не приватные сети), ответ за 10 секунд. Один адрес на проект; в настройках можно выбрать, какие события на него отправлять — по умолчанию все.

Для проверки подписи используйте webhook_secret из раздела «API-ключи» — он отличается от secret_key.

События

eventКогда отправляетсяЧто делать
invoice.paidОплата подтверждена, деньги на балансе.Отметить заказ оплаченным, выдать товар или услугу.
invoice.failedБанк отклонил платёж.Показать покупателю возможность повторить оплату (новый счёт).
invoice.expiredСрок оплаты истёк.Снять резерв товара, при необходимости выставить новый счёт.
refund.succeededВозврат покупателю выполнен; счёт в статусе refunded или partially_refunded.Отменить заказ полностью или частично, аннулировать выдачу.
refund.failedВозврат не удался, деньги вернулись на ваш баланс.Связаться с покупателем, оформить возврат другим способом.

События выплат (payout.paid, payout.rejected) появятся вместе с API выплат в следующей версии.

Формат запроса

Тело — конверт события: id события, event, createdAt и data с объектами. Для invoice.* в data.invoice — тот же объект, что возвращает GET /invoices/{id}; для refund.*data.refund и data.invoice (см. Возвраты).

ЗаголовокЗначение
X-Paydex-Signaturesha256=<hex>, где hex — HMAC-SHA256 от сырого тела запроса с ключом webhook_secret проекта.
X-Paydex-TimestampUnix-время отправки (секунды). Отклоняйте запросы старше 5 минут — защита от повторного воспроизведения.
X-Paydex-EventТип события, дублирует event из тела — удобно маршрутизировать до парсинга.
X-Paydex-Delivery-IdИдентификатор доставки, одинаковый при всех повторах одного события — ключ для дедупликации на вашей стороне.
X-Paydex-Test1 для событий тестового режима; в боевых отсутствует.
Content-Typeapplication/json

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

Алгоритм один для всех языков: взять сырые байты тела (до любого парсинга), вычислить HMAC-SHA256 с webhook_secret, добавить префикс sha256= и сравнить с заголовком функцией постоянного времени. Не пересобирайте JSON из распарсенного объекта — подпись не совпадёт.

Node.js (Express)

PHP

Python (Flask)

Go

Что отвечать

  • Любой статус 2xx — доставка считается успешной. Тело ответа не важно.
  • Любой другой статус, таймаут (10 с) или ошибка соединения — доставка неуспешна, будет повтор.
  • Отвечайте быстро: сначала 200, тяжёлую работу (письма, генерацию ключей) выполняйте в фоне.
  • Если подпись не совпала — отвечайте 401 и ничего не меняйте в заказе.

Повторы доставки

Если ваш сервер не ответил 2xx, мы повторяем доставку по расписанию: первая попытка сразу после события, затем до 6 повторов в течение ~39 часов:

Попыткаперваяповтор 1повтор 2повтор 3повтор 4повтор 5повтор 6
Задержкасразу1 мин5 мин30 мин2 ч12 ч24 ч

История попыток с кодом и телом ответа вашего сервера видна в карточке платежа в кабинете; там же кнопка «Повторить вебхук» — она отправляет событие заново в любой момент.

Идемпотентность и порядок

  • Одно и то же событие может прийти дважды (например, вы ответили 200, но ответ не дошёл). Ключ дедупликации — X-Paydex-Delivery-Id (он же id в теле): сохраните обработанные id и отвечайте 200 на повтор без действий.
  • Порядок событий разных счетов не гарантирован. Для одного счёта возможна последовательность invoice.paidrefund.succeeded.
  • Если сомневаетесь в актуальности — запросите GET /invoices/{id}: ответ API всегда отражает текущее состояние.

Тестирование

В тестовом режиме вебхуки отправляются точно так же, с подписью тем же webhook_secret — с заголовком X-Paydex-Test: 1 и "isTest": true в объекте счёта. Для локальной разработки пробросьте порт наружу любым туннелем (ngrok, cloudflared) и укажите публичный HTTPS-адрес в webhook_url. Подробнее — Тестирование.