Вебхуки
Вебхуки приложения
На странице «Вебхуки» developer-приложение настраивает отправку выбранных событий на внешний URL. Один webhook может слушать несколько типов событий, а у одного приложения может быть несколько webhooks с разными адресами и наборами событий.
Для рабочего endpoint используйте HTTPS. Одна попытка доставки ждёт ответ не более 120 секунд, но обработчику лучше быстро принять событие в собственную очередь и вернуть 2xx.
Вкладка «Общие» содержит публичные события приложения, а вкладка «Для инструментов» — запросы HTTP-инструментов из конструктора. У обоих видов есть история запросов, однако режим ожидания результата агента применяется только к инструментам.
Какие события доступны
command_start— пользователь отправил/start; вdataприходятcommandиargs;message_allow— пользователь разрешил отправку сообщений;message_new— новое сообщение пользователя; текст находится вdata.content;lead_created— создан лид;lead_unsubscribed— пользователь отписался от сообщений;lead_blocked— пользователь заблокировал бота;message_undelivered— сообщение не доставлено;error— при обработке события произошла ошибка.
Для событий, связанных с подпиской или ошибкой, объект data может содержать key и error_message. Поля, для которых нет значения, приходят как null; обработчик не должен считать их обязательными для каждого типа события.
Как создать вебхук
На странице вебхуков откройте вкладку «Общие», затем:
- Нажмите «Создать вебхук».
- В форме создания укажите полный URL обработчика.
- Отметьте один или несколько типов событий.
- Нажмите «Создать».

Новый webhook сразу получает статус «Активен».
Секрет и подпись
После создания открывается окно с секретом. Скопируйте его через кнопку копирования, сохраните в защищённом хранилище и только затем нажмите «Готово». Полный секрет показывается один раз; в списке остаётся только его короткий префикс.
Каждый запрос содержит заголовки:
Content-Type: application/json;X-App-Id— Client ID приложения;X-Webhook-Timestamp— время события, совпадающее сtimestampв теле;X-Webhook-Event-Id— уникальный ID события, совпадающий сevent_idв теле;X-Webhook-Signature— hex-строка HMAC-SHA256.
Подпись защищает всё тело запроса. Сначала JSON канонизируется: ключи каждого объекта сортируются, порядок элементов массивов сохраняется, свойства со значением undefined пропускаются, а undefined внутри массива становится null. Затем соединяются версия подписи, время, ID события и канонический JSON:
import { createHmac, timingSafeEqual } from "node:crypto";
function canonicalize(value) {
if (value === null || ["boolean", "string"].includes(typeof value)) {
return value;
}
if (typeof value === "number" && Number.isFinite(value)) {
return value;
}
if (Array.isArray(value)) {
return value.map((item) =>
item === undefined ? null : canonicalize(item),
);
}
if (typeof value === "object") {
return Object.fromEntries(
Object.keys(value)
.sort()
.filter((key) => value[key] !== undefined)
.map((key) => [key, canonicalize(value[key])]),
);
}
throw new TypeError("Unsupported webhook payload value");
}
const canonicalPayload = JSON.stringify(canonicalize(payload));
const signedContent = [
"v1",
payload.timestamp,
payload.event_id,
canonicalPayload,
].join(".");
const expectedHex = createHmac("sha256", webhookSecret)
.update(signedContent, "utf8")
.digest("hex");
const expected = Buffer.from(expectedHex, "hex");
const received = Buffer.from(request.headers["x-webhook-signature"] ?? "", "hex");
const signatureIsValid =
received.length === expected.length && timingSafeEqual(received, expected);
Перед обработкой убедитесь, что X-Webhook-Timestamp и X-Webhook-Event-Id точно совпадают с полями тела, проверьте подпись, X-App-Id, разрешённый project_id, тип события и допустимую для вашей интеграции свежесть времени. Не записывайте секрет в логи и не передавайте его в чат.
Формат запроса
Боевой запрос имеет общую форму:
{
"event_id": "019c5a23-8b7c-7f10-a4dd-c4f4b650032a",
"event_type": "message_new",
"timestamp": "2026-07-10T12:00:00.000Z",
"project_id": "project-id",
"channel_id": "channel-id",
"channel_type": "telegram",
"lead_id": "lead-id",
"dialog_id": "dialog-id",
"platform_user_id": "platform-user-id",
"data": {
"content": "Текст сообщения"
}
}
data зависит от event_type. Не привязывайте обработчик к наличию полей, которые не относятся к выбранному событию. Используйте event_id как ключ идемпотентности: сохраните уже принятые ID и не выполняйте одно событие повторно.
Тест и повторные попытки
У каждого webhook в списке есть действие «Тест». Оно выполняет один запрос с собственным event_id, event_type: "test", project_id: "test", пустыми идентификаторами и сообщением в data. Заголовки и подпись формируются по тем же правилам, что и для боевого события. Обработчик должен принимать этот служебный тип отдельно от списка боевых событий.
Тест считается успешным только при HTTP-ответе 200-299 и показывает код и время ответа. Это один немедленный запрос без повторов; он может ждать ответ до 120 секунд.
Боевое событие ставится в очередь с окном повторов в один день. При сетевой ошибке, тайм-ауте или ответе не 2xx выполняется до 12 попыток: сразу, затем примерно через 1, 5, 15 и 30 минут, 1, 2, 4, 8, 12, 18 и 24 часа. Во всех попытках сохраняются те же event_id, timestamp, тело и подпись, поэтому повтор нужно распознавать по event_id и отвечать 2xx, если событие уже надёжно принято.
Управление и замена секрета
Карточка показывает выбранные события, состояние, время последнего вызова и последний HTTP-статус. Через переключатель состояния webhook можно отключить и снова включить; отключённый webhook не получает новые боевые события.
Откройте страницу webhook, чтобы изменить URL или набор публичных событий, затем нажмите «Сохранить». Полный секрет существующего webhook повторно не показывается. Если он потерян, безопасно создайте новый webhook, переключите обработчик и только затем удалите старый.

Кнопка удаления webhook открывает подтверждение. После окончательного удаления отправка на этот URL прекращается, а секрет восстановить нельзя.
Вебхуки инструментов
Вкладка «Для инструментов» показывает HTTP-инструменты приложения и созданные для них webhook. URL, параметры и режим выполнения задаются в конструкторе инструмента; со страницы webhook можно перейти к редактированию инструмента.

- в мгновенном режиме агент ждёт один ответ, а автоматических повторов нет;
- в режиме ожидания результата запрос ставится в очередь, и агент продолжает шаг после успешной доставки;
- в фоновом режиме запрос тоже ставится в очередь, но ответ не продолжает текущий шаг агента.
Тело вызова содержит event_type: "tool_call", идентификаторы события, приложения, установки и проекта, системное имя инструмента и arguments. Обработчик должен проверять входные данные и возвращать результат, понятный агенту. Режимы, тайм-ауты, окна повторов и точный пример тела описаны в разделе «Настройки приложения».
История и восстановление доставки
На странице webhook область «Запросы» показывает операции доставки со статусами: в очереди, ожидает повтора, завершена, окончательно не доставлена или снята с обработки. Откройте операцию, затем конкретную попытку, чтобы проверить исходный JSON, HTTP-ответ либо текст сетевой ошибки и время каждой попытки.
После устранения причины используйте «Повторить»: создаётся новая операция с тем же JSON. Внешний сервис обязан распознавать повтор по event_id, иначе действие может выполниться дважды.
Для неудачного инструмента в режиме ожидания результата доступно «Повторить и продолжить». После успешного ответа ожидающий агент получает результат и продолжает выполнение. Обычный повтор проверяет доставку, но сам по себе не возобновляет ожидающего агента. Если повтор больше не нужен, отметьте проблему решённой: она исчезнет из индикатора ошибок, а история запросов сохранится.

Если события не приходят
- Убедитесь, что webhook имеет статус «Активен» и нужный тип события отмечен.
- Запустите тест и проверьте последний HTTP-код и время вызова.
- Проверьте, что внешний URL доступен по HTTPS и отвечает не позднее 120 секунд.
- Убедитесь, что обработчик принимает
Content-Type: application/jsonи служебныйevent_type: "test". - Сверьте
X-App-Id,X-Webhook-TimestampиX-Webhook-Event-Idс телом запроса. - Канонизируйте всё тело, соберите строку
v1.timestamp.event_id.canonicalPayloadи проверьте HMAC-SHA256. - Откройте историю запросов и сопоставьте сохранённый payload, ответ или ошибку с журналом внешнего сервера по
event_id. - Возвращайте
2xxтолько после того, как событие принято или надёжно поставлено в вашу очередь; повторныйevent_idне обрабатывайте заново. - Если секрет потерян, создайте новый webhook и замените старый по безопасной последовательности выше.