Для защиты от поддельных запросов каждый вебхук подписывается с помощью HMAC-SHA256. Заголовок x-webhook-signature содержит подпись в формате sha256=xxx.
Подпись передаётся в заголовке x-webhook-signature в формате sha256=xxx. Перед сравнением уберите префикс sha256=.
Используйте timing-safe сравнение
Всегда используйте функции для безопасного сравнения строк (crypto.timingSafeEqual, hmac.compare_digest, hash_equals), чтобы предотвратить timing-атаки.
Используйте RAW body
Для верификации обязательно используйте оригинальное тело запроса до парсинга JSON. Некоторые фреймворки автоматически парсят JSON, что может изменить форматирование и подпись не совпадёт.
Обрабатывайте идемпотентно
События могут приходить повторно (см. поле retryCount). Используйте id события для дедупликации и предотвращения повторной обработки.
ID счета в data.id
ID счета передается в поле data.id, а не data.invoiceId. Учитывайте это при обработке событий.
Распространённая проблема: Если ваш сервер (nginx) настроен на редирект с HTTP на HTTPS, вебхуки не будут работать!При 301 редиректе POST-запрос автоматически превращается в GET — это стандартное поведение HTTP протокола (RFC 7231).
Пример неправильного URL:
Copy
http://api.example.com/webhook
Правильный URL:
Copy
https://api.example.com/webhook
Решение: Всегда указывайте URL вебхука с протоколом HTTPS в настройках. Либо настройте nginx на использование кода 307 (Temporary Redirect), который сохраняет метод запроса.
Copy
# Вместо 301 используйте 307 для сохранения POST-методаserver { listen 80; server_name api.example.com; return 307 https://$server_name$request_uri;}