Вебхуки

События на ваш адрес: список, заголовки, проверка подписи HMAC, повторы и защита от петли.

События #

СобытиеКогдаВ data
conversation.startedпосетитель завёл обращениеconversation
message.createdновое сообщение в обе стороныconversation, message
conversation.closedобращение закрытоconversation, reason
visitor.identifiedсайт передал сведения о посетителеconversation
webhook.testпроверка из кабинета, подписаться нельзя

Имена окончательные. Новое событие добавляется рядом, старое не переименовывается никогда: по именам написаны обработчики на вашей стороне.

Как выглядит запрос #

Объекты conversation и message — те же, что отдаёт API: один разбор годится и там и там.

Запрос
POST /ваш-обработчик HTTP/1.1
Content-Type: application/json
X-WidgetChat-Event: message.created
X-WidgetChat-Delivery: message.created:8f1c…
X-WidgetChat-Attempt: 1
X-WidgetChat-Timestamp: 1755878400
X-WidgetChat-Signature: sha256=6b2f…

{"id": "message.created:8f1c…",
 "event": "message.created",
 "createdAt": "2026-08-22T12:00:00Z",
 "workspaceKey": "example-ru",
 "data": {"conversation": { … }, "message": { … }}}

Проверка подписи #

Подписывается строка timestamp + "." + body, а не одно тело: подпись голого тела можно переслать повторно хоть через сутки, и обработчик не отличил бы повтор от свежего события.

Проверяйте три вещи: подпись совпала при сравнении за постоянное время; метка времени отличается от ваших часов не больше чем на пять минут; номер из X-WidgetChat-Delivery ещё не встречался.

Пример вызова
// Go
mac := hmac.New(sha256.New, []byte(secret))
mac.Write([]byte(r.Header.Get("X-WidgetChat-Timestamp") + "." + string(body)))
expected := "sha256=" + hex.EncodeToString(mac.Sum(nil))
ok := hmac.Equal([]byte(expected), []byte(r.Header.Get("X-WidgetChat-Signature")))
Запрос
# PHP
$expected = 'sha256=' . hash_hmac('sha256', $timestamp . '.' . $body, $secret);
$ok = hash_equals($expected, $signature);

Ответы и повторы #

Ждём ответ 20 секунд. Отвечайте сразу, а работу делайте после — долгий обработчик считается неудачей. Все попытки видны в журнале доставок в кабинете: событие, номер попытки, код ответа, текст ошибки.

Ваш ответЧто делаем
2xxсчитаем принятым, больше не шлём
4xxповтора не будет: получатель не изменит мнения
5xx, таймаут, обрыв3 попытки, пауза 5 секунд и дальше вдвое

Защита от петли #

На ответ, отправленный вашей же программой, тоже придёт message.created. Смотрите поле origin внутри message: api — это вы сами, telegram — оператор из группы, bitrix24, amocrm, retailcrm — менеджер из CRM, widget — посетитель.

Требования к адресу #

Только https и только внешний адрес: событие несёт переписку клиента. Адрес во внутренней сети принят не будет.