Webhook

2 июня 2026 · ~16 мин чтения

протокол интеграция веб http история

Webhook

Webhook (буквально «веб-крючок») — это договорённость между двумя сервисами: когда у первого происходит интересное событие, он сам делает HTTP-запрос на заранее зарегистрированный адрес второго и приносит туда данные о событии. Это инверсия привычной модели «клиент спрашивает — сервер отвечает»: тут сервер сам зовёт клиента, как только есть что сказать.

История

Термин «webhook» придумал и популяризовал американский разработчик Джефф Линдсей (Jeff Lindsay) в мае 2007 года — в посте «Web hooks to revolutionize the web» в своём блоге progrium.com. До этого похожие идеи носили другие названия: «HTTP callback», «PubSub», «push notification», но именно у Линдсея получилось ёмкое слово, которое прижилось.

Какую проблему решали в 2007 году. Веб тогда уже был большим, но интеграции между сервисами строились через polling — клиент дёргает API раз в N минут «есть новости?». Это работало, но было расточительно: 99% запросов возвращали «нет, ничего нового». Если ты хотел узнать о новой записи в чужом блоге, тебе либо приходилось опрашивать его RSS-ленту раз в полчаса, либо ставить тяжёлые инфраструктурные штуки вроде XMPP или Jabber-серверов. Линдсей предложил очень простую идею: «давайте просто разрешим сервисам слать друг другу HTTP POST, когда есть событие. Никаких новых протоколов. Просто URL и тело запроса».

Вехи развития:

Текущий статус: webhook — это не один протокол, а паттерн поверх HTTP. Никто не владеет «торговой маркой», нет одного стандарта (хотя есть попытки — Standard Webhooks от 2022 года, инициатива Svix). Каждый сервис делает по-своему: где-то JSON, где-то form-encoded, где-то XML; подпись где-то HMAC-SHA256, где-то JWT, где-то вообще нет.

Что это такое

Webhook — это обратный HTTP-запрос от сервера к клиенту в ответ на событие. Слово «обратный» здесь ключевое: в классическом веб-взаимодействии клиент (твой браузер, твой код) первым стучится к серверу, и сервер отвечает. В webhook-модели роли меняются — это сервис, у которого случилось событие, сам становится клиентом и стучится к твоему серверу.

Технически webhook — это всегда HTTP-запрос (чаще всего POST, иногда PUT) на URL, который ты заранее указал у источника событий. В теле запроса — данные о событии, обычно в формате JSON. Твой сервер должен:

  1. Слушать этот URL и принимать запросы.
  2. Прочитать payload, понять что произошло.
  3. Сделать что-то полезное (записать в БД, послать сообщение, обновить статус).
  4. Вернуть HTTP-код 200 (или 2xx), чтобы источник понял: «принято».

Если ты вернул 5xx или вообще не ответил — источник, скорее всего, попробует прислать запрос ещё раз через минуту, через 10 минут, через час. Это называется retry policy (политика повторов).

Webhook vs Polling. Polling — это когда клиент сам периодически спрашивает «есть новости?». Webhook — когда сервер сам говорит «новости есть, лови». Разница как между «звонишь сам в магазин каждый час: привезли ли заказанный диван» и «магазин звонит тебе, когда диван приехал». Polling простой, но тратит ресурсы и даёт задержку (узнаешь только при следующем опросе). Webhook эффективнее по ресурсам и почти мгновенный, но требует, чтобы у тебя был публичный URL.

Webhook vs API. Это не альтернативы, а дополнения. API — это про «я хочу что-то сделать или узнать прямо сейчас». Webhook — про «дай знать, когда что-то случится». В Stripe ты дёргаешь API, чтобы списать деньги, и слушаешь webhook, чтобы узнать что списание реально прошло (потому что 3D-Secure, банк-эмитент и прочие задержки могут добавить минуты).

Webhook vs WebSocket. WebSocket — это постоянное двустороннее соединение, которое держится открытым часами. Webhook — это серия одноразовых HTTP-запросов. WebSocket хорош для чата и онлайн-игр, где сообщения летают каждые миллисекунды. Webhook — для редких бизнес-событий: «платёж прошёл», «лид пришёл», «коммит запушен».

Webhook vs Callback (в коде). В программировании «callback» — это функция, которую ты передаёшь куда-то, чтобы её вызвали потом. Webhook — буквально та же идея, только не функция, а URL, и вызов через сеть, а не в памяти процесса. Иногда webhook так и называют — «HTTP callback».

Аналогии из жизни

Аналогия 1: курьер с домофоном. Polling — это когда ты каждые пять минут спускаешься во двор «ну где же мой курьер». Webhook — когда ты дал курьеру свой код домофона, курьер сам нажимает на кнопку, когда подошёл, и ты идёшь открывать.

Где ломается: если домофона нет (нет публичного URL, ты за NAT-роутером без проброса портов), курьер не сможет тебя позвать — придётся всё-таки выходить и проверять. И ещё: если ты не услышал звонок (сервер лежал), курьер постоит, позвонит ещё раз, а потом уйдёт. Поэтому у webhook всегда есть retry policy, а у тебя должна быть готовность принять «звонок» повторно, не запутавшись (см. идемпотентность).

Аналогия 2: подписка на доставку газеты. Раньше ты приходил в киоск каждое утро и смотрел, вышел ли свежий номер (polling). Подписка работает наоборот: газета сама приходит в твой почтовый ящик в день выхода (webhook). Адрес доставки ты сообщил один раз при оформлении подписки — это и есть «регистрация webhook URL».

Где ломается: почтальон не знает, прочитал ли ты газету. Если ящик переполнен или ты переехал, газета будет лежать в подъезде или вернётся отправителю. С webhook так же: если твой сервер ответил 200, источник считает «доставлено» и забывает — даже если у тебя внутри код упал и реально событие не обработалось. Поэтому грамотная схема — сначала записать payload «как есть» в свою очередь, ответить 200, и только потом разбирать.

Аналогия 3: радио-маяк аэропорта. Маяк не знает, кто его слушает. Он просто кричит «вот моя позиция» в эфир, а все приёмники, кто на него настроен, ловят сигнал. Только это аналогия для pub/sub (издатель/подписчик), а не строго для webhook: webhook обычно адресный — конкретный URL.

Где ломается: маяк широковещателен — webhook индивидуален. Если у источника 10 000 подписчиков и нужно разослать им всем уведомление, источнику придётся сделать 10 000 отдельных HTTP-запросов. Это нагрузка, и поэтому крупные сервисы (Slack, GitHub) ограничивают количество подписчиков на одно событие или предлагают использовать pub/sub поверх специальной шины сообщений (Kafka, EventBridge), а не webhook.

Как это работает

Жизненный цикл webhook условно делится на три этапа: регистрация → доставка → обработка.

Этап 1. Регистрация.

Ты идёшь в админку источника событий (или через его API) и говоришь: «Когда у тебя случается событие типа payment.succeeded, шли POST на https://my-server.com/hooks/stripe». Источник запоминает: «такой-то аккаунт хочет такие-то события на такой URL». Часто при регистрации генерируется секрет (shared secret) — длинная случайная строка, которой обе стороны будут пользоваться для подписи.

Этап 2. Доставка.

У источника случается событие. Он формирует payload (объект с описанием события — обычно JSON), вычисляет подпись HMAC-SHA256(secret, body), открывает HTTP-соединение к твоему URL и делает запрос:

POST /hooks/stripe HTTP/1.1
Host: my-server.com
Content-Type: application/json
Stripe-Signature: t=1738012345,v1=5257a869e7ecebeda32...
User-Agent: Stripe/1.0 (+https://stripe.com/docs/webhooks)

{
  "id": "evt_1Mvz8...",
  "type": "payment_intent.succeeded",
  "created": 1738012345,
  "data": { "object": { "amount": 100000, "currency": "rub", ... } }
}

Дальше источник ждёт ответ — обычно с таймаутом 5–30 секунд. Что бы ни случилось — твой сервер должен уложиться. Если ответил 2xx — событие считается доставленным. Если 4xx — источник, как правило, не повторяет (значит, ты сам отказался). Если 5xx или таймаут — включается retry policy: повторы с экспоненциальным интервалом (1 минута → 5 минут → 30 минут → час → 6 часов → день), обычно в течение 3–7 суток. После исчерпания попыток событие отправляется в «архив недоставленных» или просто теряется, в зависимости от сервиса.

Этап 3. Обработка.

Твой сервер получает запрос. Хорошая схема выглядит так:

  1. Проверить подпись. Берёшь заголовок Stripe-Signature (или X-Hub-Signature, или как назвал источник), вычисляешь HMAC от тела запроса с тем же секретом, сравниваешь. Не совпало — отвечаешь 401 и логируешь. Это защита от подделок: без секрета злоумышленник не сможет имитировать webhook от Stripe.
  2. Записать payload в очередь. Не пытайся обработать прямо в HTTP-обработчике — слишком долго, источник отключится по таймауту. Сохрани событие в свою БД или очередь и сразу верни 200.
  3. Проверить идемпотентность. Источник может прислать одно и то же событие дважды (например, ты ответил 200, но ответ не дошёл, и через минуту он повторил). У каждого события обычно есть уникальный ID (evt_1Mvz8... у Stripe). Если ты уже видел этот ID — игнорируй.
  4. Сделать дело. Фоновый воркер берёт событие из очереди, обновляет статус заказа, шлёт письмо клиенту, пишет в CRM. Если что-то падает — воркер ретраит сам, источник об этом уже не знает.

ASCII-схема всего цикла:

   ┌──────────────┐                              ┌──────────────┐
   │   Источник   │  1. регистрация URL+secret   │   Получатель │
   │   (Stripe)   │<─────────────────────────────│  (my-server) │
   └──────┬───────┘                              └──────┬───────┘
          │                                              │
          │ ───── событие случилось ─────                │
          │                                              │
          │  2. POST /hooks/stripe + HMAC                │
          │ ────────────────────────────────────────────>│
          │                                              │  3. проверить
          │                                              │     подпись,
          │                                              │     в очередь
          │  4. HTTP 200 OK                              │
          │ <────────────────────────────────────────────│
          │                                              │
          │  (если 5xx или таймаут — retry через 1m,     │
          │   5m, 30m, 1h, 6h, 24h …)                    │
          ▼                                              ▼

Ключевое

Webhook — это не «технология», а договорённость двух сторон поверх HTTP. Все «фишки» webhook (подписи, ретраи, идемпотентность, версионирование) — это надстройки, которые каждый сервис делает по-своему. Если ты выкатил свой webhook, ты сам отвечаешь за качество этой договорённости.

Где встречается в обычной жизни

Ты сталкиваешься с webhook практически каждый день, не зная этого слова:

Где встречается в IT и бизнесе

Кто пользуется

Конкретные крупные пользователи webhook'ов — это, считай, все продукты, которые делают B2B SaaS:

Альтернативы и конкуренты

Когда НЕ стоит использовать

Главный грабли

Никогда не доверяй webhook без проверки подписи. Любой, кто узнал твой публичный URL (а это легко — он в DNS, его видят CDN, прокси, логи), может слать на него поддельные запросы. Если ты на основе webhook'а от «Stripe» (на самом деле — от хакера) активируешь подписку — поздравляю, ты раздаёшь премиум-аккаунты бесплатно. Проверка HMAC-подписи — обязательна.

Связанные понятия

Литература и источники

Где встретилось у меня

Понятие всплыло вчера в нескольких задачах. В одном из бот-проектов (для платформы MAX) приём входящих сообщений построен ровно по webhook-схеме: внешняя платформа стучится к серверу бота, бот разбирает payload и пишет в БД. В соседнем проекте (управление рекламными ссылками) у каждого проекта в БД есть поле для URL вебхука колл-центра — туда отправляется уведомление о новой заявке, чтобы оператор не дёргал систему руками. Также вчера разбирался поток данных «лидогенератор → бренд-бот»: и там, и там — webhook'и c подписью и очередью на принимающей стороне.

Краткое резюме