Зачем платежам вебхуки
Зачем он нужен криптоплатежам
Потому что расчёт здесь асинхронный и медленный по меркам веб-запроса.
Карточная авторизация возвращает ответ за секунду, поэтому мерчант держит HTTP-запрос открытым и отвечает клиенту сразу. Криптоплатёж ждёт сеть: секунды в Solana, минуты в Ethereum, до часа в биткоине при нескольких подтверждениях.
Держать запрос открытым столько времени невозможно. Поэтому касса сообщает клиенту, что платёж подтверждается, а шлюз присылает вебхук, когда подтверждение произошло, и в этот момент ваша система выполняет заказ.
Что содержит платёжный вебхук
Пять вещей, и каждая нужна по своей причине.
Референс заказа, чтобы вы знали, о каком заказе речь. Статус, ради которого сообщение и отправлено. Фактически полученную сумму и актив, что позволяет обнаружить недоплату. Хэш транзакции как ваша учётная запись об операции. И фиатный эквивалент на момент поступления, а это та цифра, которая нужна бухгалтерии.
Чем вебхук отличается от опроса
Разница практическая, и выбор влияет на нагрузку.
Опрос означает, что ваш сервер сам спрашивает провайдера о статусе заказа с какой-то периодичностью. Работает это без всякой настройки со стороны провайдера и создаёт лишние запросы: подавляющая часть их возвращает «изменений нет».
Вебхук переворачивает направление, и сообщение приходит в момент события. Взамен вам нужен публично доступный адрес и проверка подписи.
Разумная практика такая: вебхуки как основной канал, опрос как страховка для заказов, по которым уведомление почему-то не пришло.
Как обрабатывать их правильно
Проверка подписи не опциональна
Самый важный абзац здесь.
Адрес приёма вебхуков это публичный URL, и любой, кто его найдёт, может отправить туда сообщение с утверждением, что платёж прошёл. Обработчик, зачисляющий заказы по тому, что к нему пришло, раздаст товар всякому, кто обнаружит этот адрес.
Провайдеры подписывают каждый вебхук, обычно кодом HMAC по всему содержимому с общим секретом. Ваш обработчик пересчитывает подпись и отвергает всё, что не сошлось. Пропуск этого шага это самая частая уязвимость в платёжных интеграциях, и она хуже отсутствия интеграции вообще.
То же работает в обратную сторону: никогда не зачисляйте заказ по тому, что браузер клиента попал на страницу успешной оплаты. Браузер под контролем клиента. Вебхук нет.
Дубли это норма
Вебхуки доставляются не менее одного раза; ровно одного раза протокол не обещает.
Провайдер, отправивший сообщение и не получивший подтверждения, повторяет отправку, причём исходное сообщение могло и дойти. Сетевые условия дают тот же результат. Значит, ваша система получит одно и то же уведомление дважды, и отношение к этому как к ошибке ведёт к дважды выполненным заказам.
Лечится идемпотентностью: фиксируйте, какие идентификаторы уведомлений вы уже обработали, и повторы игнорируйте. Сделайте выполнение заказа безопасным при повторной попытке. Это стандартная практика платёжных интеграций, и точно так же она применяется к массовым выплатам, где повторный прогон платит всем дважды без всякой возможности отозвать.
Повторы и что возвращать
Возвращайте статус 200 быстро, до выполнения медленной работы.
Провайдеры повторяют отправку при любом неуспешном ответе, обычно с растущими интервалами в течение часов или дней. Обработчик, выполняющий обработку до ответа, рискует упасть в таймаут, вызвать повтор и обработать то же событие снова.
Сначала подтвердите приём, затем положите работу в очередь и обрабатывайте асинхронно.