Webhook должен быть идемпотентным
Провайдер может повторить событие из-за timeout или неуспешного HTTP-кода. Храните уникальный event_id с UNIQUE-ограничением и возвращайте 2xx повтору без повторной бизнес-операции.
Правильный порядок обработки
| Шаг | Действие |
|---|---|
| 1 | прочитать raw body |
| 2 | проверить подпись по документации сервиса |
| 3 | разобрать JSON |
| 4 | получить event_id |
| 5 | проверить, не обработан ли он ранее |
| 6 | |
| ранить событие/поставить в очередь | |
| 7 | быстро вернуть 2xx |
| 8 | |
| ронно |
Каркас webhook с HMAC
$raw = file_get_contents('php://input');
$secret = getenv('WEBHOOK_SECRET');
$received = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '';
$expected = hash_hmac('sha256', $raw, $secret);
if (!$received || !hash_equals($expected, $received)) {
http_response_code(401);
exit('invalid signature');
}
$event = json_decode($raw, true);
$eventId = (string)($event['id'] ?? '');
if ($eventId === '') {
http_response_code(400);
exit('missing event id');
}
// Проверить eventId в БД.
// Если уже обработан — вернуть 200.
// Иначе сохранить событие и поставить в очередь.
http_response_code(200);
echo 'ok';Не придумывайте формат подписи сами
Заголовок, алгоритм, кодировка и строка для подписи отличаются у сервисов. Используйте HMAC-пример только как каркас и сверяйте его с документацией конкретного API.
Почему надо отвечать быстро
Если внутри webhook ждать CRM, отправку почты и десяток SQL-запросов, провайдер может посчитать доставку неуспешной и отправить событие повторно. Быстрый приём + очередь надёжнее.
Что логировать
| Поле | Можно |
|---|---|
| event_id | да |
| event_type | да |
| received_at | да |
| status/attempts | да |
| HTTP status provider | да |
| секрет/токен | нет |
| полные платёжные реквизиты | нет |
| лишние персональные данные | нет |
Скачать примеры для веб-разработки
Связанные материалы
Безопасная обработка webhook
Сервер должен проверять подлинность входящего события по механизму провайдера, ограничивать размер тела запроса и не выполнять произвольные команды из полученных данных. Сохраняйте идентификатор события и не обрабатывайте один и тот же webhook дважды; доставка «как минимум один раз» — распространённое поведение внешних сервисов.
Быстрый ответ приёмника и дальнейшая обработка через очередь уменьшают риск таймаутов. Проверяйте также события, пришедшие не по порядку, и ручной повтор после временного сбоя.