Insights / Технические материалы
Безопасная обработка Webhook платежей и возвратов: сверка состояния в Workers
Пример реализации, в котором отдельно рассматриваются проверка подписи, повторные и задержанные события, состояние возврата и ответы внешних API. Также показана повторная проверка прав перед административной операцией.

Содержание
Проверяйте платёжные webhook в Workers повторной доставкой и изменением порядка событий в тестовой среде, исключая двойное обновление состояния. Сверяйте обработку перенаправлений внешних API с Cloudflare Workers: Request и средой выполнения; отдельно фиксируйте приём, внешнее состояние и дальнейшие действия.
Получение события от платёжного сервиса само по себе не завершает заказ или возврат. В этом анонимизированном примере показано, как административный процесс в Workers сверяет состояние провайдера с локальными записями. Данные клиентов, реальные идентификаторы транзакций и внутренние адресаты уведомлений не раскрываются.
Проверяйте подпись и блокируйте повторную обработку на входе
Проверяйте подпись по неизменённому исходному телу запроса и сверяйте режим события с ожидаемым production или test. Записывайте обработку и захватывайте блокировку, чтобы повторная доставка того же события не повторяла бизнес-операцию. Это не гарантирует упорядоченную доставку событий. См. официальное руководство Stripe по Webhook.
При задержанном событии о возврате запрашивайте текущее состояние провайдера
Реализация обрабатывает refund.created, refund.updated и refund.failed. Для управляемого возврата она повторно получает текущий объект Stripe, чтобы позднее событие не вернуло локальную запись к старому состоянию. Перед решением о полном возврате заказа суммы успешных и ожидающих возвратов учитываются отдельно.
Проверяются сумма, валюта, PaymentIntent, metadata для связи заказа и операции, а также ранее сохранённые идентификаторы. ID платежа может начинаться с py_, а ID возврата — с pyr_. Реализация изменена так, чтобы корректный ответ не отклонялся только из-за отличия от одного известного префикса. Поддержка дополнительного префикса не ослабляет проверки суммы и идентичности. Неизвестные значения не считаются нулём.
Разделяйте результаты возврата, баллов и уведомлений
Проверяйте баланс и полномочия до запроса возврата, а затем ещё раз проверяйте полномочия и срок действия операции после чтения внешнего состояния и непосредственно перед записью. Используйте ключ идемпотентности и блокировку для каждой операции. Если внешний результат неизвестен, сверяйте текущее состояние вместо безусловного повторного запроса возврата.
Успешный возврат и успешная корректировка баллов — разные состояния. Последующая ошибка не должна повторно запускать возврат; необходимую сверку или исправление следует записать. Настройка уведомлений, фактическое получение сообщения и последующая работа сотрудника — отдельные критерии приёмки, не относящиеся к обработке платёжных событий. Эта статья не утверждает, что уведомления работают.
- Проверка на входе Проверьте исходный body, mode и event ID; выявите повторную доставку и обработку в процессе.
- Сверка текущего состояния Не возвращайте запись к старому состоянию из-за задержанного события; сравните сумму, валюту и заказ.
- Раздельная фиксация результатов У возврата, баллов и уведомлений разные состояния. При неизвестном результате провайдера сначала сверяйте, а не повторяйте операцию.
Проверяйте ответы и в Node, и в среде Workers
Тестирование внешнего fetch только в Node может не выявить различий среды Workers. В этом случае воспроизвели проблему совместимости с redirect: 'error' и перешли на redirect: 'manual' с явной проверкой HTTP-статуса. Не разбирайте ответ 3xx или страницу ошибки как обычный JSON и не переходите автоматически на другой хост, передавая данные авторизации. См. API Request для Workers.
Фиксируйте границы выпуска и приёмки
Изменения базы данных, зависимая обработка и интерфейс управления были развёрнуты по порядку. Проверены тесты, CI, production-страницы только для чтения и соответствие результатам запросов к API провайдера. Тестовые денежные операции клиентов не выполнялись. При экспорте CSV ячейки, которые могут интерпретироваться как формулы, обрабатываются как текст; неизвестные комиссии не заменяются нулём.
О границе входа в панель управления см. Проектирование сеансов для нескольких сервисов.