Вебхуки
Вебхук — 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-Signature | sha256=<hex>, где hex — HMAC-SHA256 от сырого тела запроса с ключом webhook_secret проекта. |
X-Paydex-Timestamp | Unix-время отправки (секунды). Отклоняйте запросы старше 5 минут — защита от повторного воспроизведения. |
X-Paydex-Event | Тип события, дублирует event из тела — удобно маршрутизировать до парсинга. |
X-Paydex-Delivery-Id | Идентификатор доставки, одинаковый при всех повторах одного события — ключ для дедупликации на вашей стороне. |
X-Paydex-Test | 1 для событий тестового режима; в боевых отсутствует. |
Content-Type | application/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.paid→refund.succeeded. - Если сомневаетесь в актуальности — запросите
GET /invoices/{id}: ответ API всегда отражает текущее состояние.
Тестирование
В тестовом режиме вебхуки отправляются точно так же, с подписью тем же webhook_secret — с заголовком X-Paydex-Test: 1 и "isTest": true в объекте счёта. Для локальной разработки пробросьте порт наружу любым туннелем (ngrok, cloudflared) и укажите публичный HTTPS-адрес в webhook_url. Подробнее — Тестирование.