Webhook часто воспринимают как простой HTTP-запрос: сервис отправил JSON, обработчик создал сделку в CRM или ответил боту — готово. На практике проблемы начинаются именно после первого рабочего прототипа. Событие приходит повторно, внешний API отвечает медленно, сервер возвращает 500 после уже выполненной операции, а через минуту запускается retry и создаёт дубль.
Для CRM, ботов, интернет-магазинов и внутренних автоматизаций надёжность важнее красивой схемы из стрелок. Интеграция должна уметь отличать повтор от нового события, проверять отправителя, быстро подтверждать приём, безопасно повторять временные ошибки и сохранять состояние обработки.
Если нужно связать сайт, CRM, Telegram или другую систему, подобные задачи входят в CRM/API-интеграции A.S Groups.
Надёжный поток webhook-события
- ПриёмEndpoint принимает запрос только по HTTPS и проверяет формат
- АутентификацияПроверяется подпись, secret token или другой механизм источника
- IdempotencyDelivery ID или event ID сверяется с журналом обработанных событий
- ПодтверждениеИсточник быстро получает корректный 2XX
- ОчередьТяжёлая работа выполняется отдельно от входящего HTTP-запроса
- RetryВременные ошибки повторяются ограниченно и предсказуемо
- КонтрольНеобработанные события попадают в журнал или dead-letter queue
Главный принцип: подтверждение доставки и выполнение бизнес-операции — разные этапы. Один не должен блокировать другой.
Почему webhook может прийти повторно
Повторная доставка сама по себе не является ошибкой сервиса. Отправитель может не получить ответ из-за сетевого таймаута, промежуточного прокси или временного сбоя. При этом обработчик уже мог выполнить действие: создать лид, списать остаток, отправить уведомление.
Поэтому схема «получили POST → сразу сделали действие» безопасна только для очень простых случаев. В рабочих интеграциях нужно исходить из предположения, что одно и то же событие может быть доставлено повторно.
Idempotency: как не создавать дубль
Idempotency означает, что повторное выполнение одной логической операции не меняет итог после первого успешного выполнения. Для webhook это обычно достигается журналом уникальных идентификаторов событий.
GitHub, например, рекомендует использовать заголовок X-GitHub-Delivery, чтобы отслеживать уникальность доставки. Если источник отдаёт стабильный event_id, его можно сохранять в таблице обработанных событий с уникальным индексом.
CREATE TABLE processed_events (
event_id TEXT PRIMARY KEY,
status TEXT NOT NULL,
created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
);
Перед созданием сделки или отправкой сообщения обработчик пытается зарегистрировать событие. Если такой ключ уже существует и операция завершена, повтор можно подтвердить без второго бизнес-действия.
Когда одного event_id недостаточно
Иногда поставщик не даёт уникального ID. Тогда ключ можно строить из стабильных полей: тип события + ID объекта + версия/время изменения. Но такой ключ нужно проектировать аккуратно, иначе разные события случайно будут считаться одним.
Проверка подписи webhook
Публичный endpoint доступен всему интернету. Наличие длинного URL не является аутентификацией. Если сервис поддерживает webhook secret или HMAC-подпись, обработчик должен проверять её до выполнения бизнес-логики.
GitHub в официальных рекомендациях советует использовать webhook secret, HTTPS и проверку SSL. Telegram Bot API при настройке webhook поддерживает secret_token: Telegram отправляет его в заголовке X-Telegram-Bot-Api-Secret-Token, и сервер может сверить значение с ожидаемым.
Секреты нельзя хранить в клиентском JavaScript, публичном репозитории или логах. Для серверной среды их лучше держать в Secrets/Environment Variables конкретной платформы.
Почему обработчик должен быстро отвечать 2XX
Чем дольше входящий HTTP-запрос ждёт завершения CRM, AI-модели, Google Sheets или другого API, тем больше риск таймаута. GitHub рекомендует отвечать на webhook в пределах 10 секунд и предлагает переносить тяжёлую работу в очередь.
Практическая схема выглядит так: endpoint проверяет запрос, регистрирует событие, помещает задачу в очередь и возвращает 2XX. Отдельный consumer уже создаёт сделку, вызывает API, обновляет таблицу и отправляет уведомления.
Retry: повторять только временные ошибки
Не каждая ошибка заслуживает повторной попытки. HTTP 429, сетевой таймаут или временный 5xx часто можно повторить. Ошибка валидации, неверный токен или отсутствующий обязательный ID обычно требуют исправления данных или конфигурации.
| Ситуация | Что делать | Почему |
|---|---|---|
| Timeout | Повтор с задержкой | Сервис мог быть временно недоступен |
| 429 Too Many Requests | Retry с backoff | Нужно снизить частоту запросов |
| 500/502/503 | Ограниченный retry | Временный сбой внешнего API |
| 400 validation error | Не повторять автоматически | Payload останется неправильным |
| 401/403 | Проверить авторизацию | Повтор тем же токеном обычно бессмыслен |
| Duplicate event | Вернуть успех без второго действия | Событие уже обработано |
Очередь между webhook и CRM
Очередь полезна, когда внешний API может тормозить, есть всплески событий или операция состоит из нескольких шагов. Cloudflare Queues, например, поддерживает retry, задержки и dead-letter queue. Это позволяет отделить скорость приёма webhook от скорости обработки downstream-системы.
Очередь не отменяет idempotency. Сообщение внутри очереди тоже может быть доставлено повторно при ошибке consumer, поэтому проверка уникального event ID остаётся обязательной для операций, которые нельзя безопасно повторять.
Dead-letter queue
DLQ — отдельная очередь для сообщений, которые исчерпали разрешённое число попыток. В Cloudflare Queues сообщение после достижения max_retries может быть отправлено в настроенную dead-letter queue вместо безвозвратного удаления.
Это удобно для бизнес-событий: неуспешную заявку можно расследовать, исправить данные и переотправить, а не искать её по разрозненным логам.
Журнал событий важнее обычного error.log
Для интеграции полезно хранить не весь сырой payload бессрочно, а минимальный диагностический набор: event ID, тип события, источник, время приёма, статус обработки, число попыток, внешний ID результата и короткую ошибку.
{
"event_id": "evt_123",
"source": "website",
"type": "lead.created",
"status": "processed",
"attempts": 1,
"external_id": "crm_845"
}
Токены, Authorization headers, пароли, полные банковские данные и лишние персональные сведения в такой журнал попадать не должны.
Сценарий: сайт → CRM → Telegram
Форма на сайте создаёт событие lead.created. Endpoint проверяет подпись, создаёт запись по event ID и помещает задачу в очередь. Consumer создаёт сделку в CRM, сохраняет полученный CRM ID, затем отправляет менеджеру уведомление в Telegram.
Если Telegram временно недоступен, не нужно заново создавать сделку. Каждый шаг должен иметь собственный статус. Тогда retry повторит только неуспешное уведомление.
Именно такие многосистемные сценарии относятся к автоматизации бизнес-процессов.
Сценарий: бот → CRM
Бот собирает имя, телефон и параметры заявки. На финальном шаге формируется стабильный ключ, например ID диалога + номер заявки. Если пользователь дважды нажал кнопку или платформа повторила update, CRM не должна получать две одинаковые сделки.
При этом сообщения пользователю и запись в CRM лучше учитывать раздельно: CRM может успешно создать лид, а отправка ответа в мессенджер — завершиться временной ошибкой.
Чек-лист надёжной webhook/API-интеграции
- Endpoint работает только по HTTPS
- Проверяется подпись или secret token источника
- Есть стабильный event/delivery ID
- Уникальный ID защищён индексом или другой атомарной проверкой
- Повторное событие не создаёт дубль
- Входящий endpoint быстро возвращает 2XX
- Тяжёлая обработка вынесена из request path
- Retry ограничен и применяется только к временным ошибкам
- Есть журнал статусов и числа попыток
- После лимита retry событие не исчезает бесследно
- Секреты и персональные данные не пишутся в лог
- Есть ручной способ повторить конкретное неуспешное событие
Когда простого webhook достаточно
Если событие редкое, операция короткая и получатель надёжный, можно обойтись без отдельной очереди. Но проверка подписи, журнал event ID и защита от дублей всё равно полезны: именно они делают повторную доставку безопасной.
Когда нужна очередь
Очередь становится оправданной при всплесках трафика, медленных downstream API, нескольких последовательных действиях, необходимости retry с задержкой или требовании не терять заявки при временной недоступности CRM.
Частые вопросы
Почему webhook создаёт дубли в CRM?
Чаще всего одно событие доставляется повторно, а обработчик не хранит уникальный event ID и каждый POST считает новой заявкой.
Нужно ли всегда использовать очередь?
Нет. Для коротких и редких операций можно работать напрямую. Очередь особенно полезна при медленных API, всплесках событий и необходимости управляемого retry.
Можно ли определять дубль по телефону клиента?
Это рискованно. Один клиент может отправить две разные заявки. Лучше использовать уникальный ID события или операции, а телефон оставить бизнес-атрибутом.
Что делать, если источник не поддерживает подпись?
Использовать доступные механизмы: секретный заголовок, allowlist IP при стабильных адресах, собственный токен и строгую валидацию payload. Но это зависит от возможностей конкретного сервиса.
Что такое exponential backoff?
Это увеличение задержки между повторными попытками. Такой подход снижает нагрузку на сервис, который уже испытывает проблемы, и помогает не превратить временный сбой в лавину запросов.
Что хранить в журнале webhook?
Event ID, тип, источник, время, статус, число попыток и ID созданного объекта. Секреты и лишние персональные данные хранить не следует.
Можно ли повторно запустить неуспешное событие вручную?
Да, и это полезная функция. При наличии журнала или DLQ можно исправить причину и переобработать конкретное событие без повторной отправки всей цепочки.
Официальные источники
- GitHub Docs — Best practices for using webhooks
- Cloudflare Queues — Overview
- Cloudflare Queues — Batching, Retries and Delays
- Cloudflare Queues — Dead Letter Queues
- Telegram Bot API — setWebhook
Нужна интеграция CRM, сайта или бота?
Перед разработкой полезно описать источник события, целевую систему, обязательные поля, допустимое время задержки и правила повторов. После этого можно спроектировать endpoint, idempotency, очередь и контроль ошибок без лишней сложности. Обсудить интеграцию с A.S Groups.
Обсуждение
Вопросы и комментарии
Можно уточнить детали статьи или поделиться своим опытом. Первый комментарий проходит проверку.