Webhook (вебхук, хук) — HTTP-коллбэк: при наступлении определённого события поставщик данных автоматически отправляет POST-запрос на URL, заранее зарегистрированный получателем. Этим webhooks принципиально отличаются от традиционных API: в API клиент опрашивает сервер (pull), в webhooks сервер сам толкает данные клиенту (push).
Как работает webhook
- Получатель регистрирует свой URL (endpoint) в настройках поставщика: например,
https://myapp.com/webhooks/github. - При событии (push в репозиторий, успешный платёж, сообщение в чате) поставщик формирует JSON-пакет с данными о событии.
- Поставщик отправляет HTTP POST на зарегистрированный URL.
- Получатель обрабатывает запрос и возвращает HTTP 200. Если вернулся не 200 — поставщик повторит доставку через некоторое время.
Из-за механизма повторных попыток обработка webhook должна быть идемпотентной: одно и то же событие, доставленное дважды, не должно вызывать дублирование действий.
Безопасность webhook
Поскольку URL эндпоинта публичный, нужно верифицировать, что запрос пришёл именно от ожидаемого поставщика:
- HMAC-подпись. GitHub, Stripe, Slack подписывают тело запроса секретным ключом и передают подпись в заголовке (например,
X-Hub-Signature-256). Получатель сам вычисляет HMAC и сравнивает. - Timestamp + replay protection. Заголовок со временем события позволяет отклонять запросы старше 5 минут.
- IP whitelist. Stripe публикует список IP своих серверов — можно фильтровать на уровне файрвола.
История
Термин «webhook» ввёл разработчик Jeff Lindsay в 2007 году в своём блоге как концепцию «user-defined HTTP callbacks». GitHub реализовал webhooks в 2008 году для уведомления сторонних систем о push-событиях — это стало стандартом для CI/CD. К 2010-м webhooks приняли Stripe (платежи), Twilio (SMS/звонки), Slack (сообщения). Сегодня webhooks — стандартный механизм интеграции в event-driven архитектурах.
Webhook vs Polling vs WebSocket
| Метод | Принцип | Задержка | Нагрузка |
|---|---|---|---|
| Polling | Клиент опрашивает сервер каждые N секунд | До N секунд | Высокая при редких событиях |
| Webhook | Сервер толкает данные клиенту | Секунды | Минимальная |
| WebSocket | Постоянное двустороннее соединение | Миллисекунды | Постоянная overhead |
Webhook: надёжная доставка и идемпотентность
Для надёжной обработки webhook необходимо: возвращать HTTP 200 быстро (до 5-30 сек, в зависимости от провайдера), а тяжёлую обработку выполнять асинхронно через очередь задач (Celery, RQ, бэкграунд-воркер). Если эндпоинт не ответил 200 в срок — провайдер повторит доставку. Без идемпотентности повторная доставка вызовет дублирование действий.
Реализация идемпотентности: сохранять ID события (delivery_id из заголовка) в БД и проверять перед обработкой. Stripe использует Stripe-Signature с HMAC-SHA256 и timestamp для replay protection. Структура таблицы: processed_webhooks(event_id VARCHAR PRIMARY KEY, processed_at TIMESTAMP). Очередь webhook: если основной сервер перегружен или недоступен — провайдер ставит доставку в очередь (Stripe повторяет 72 часа).