Вебхуки для новых лидов
Вебхук отправляет каждый новый лид из ваших чат-каналов, например из чата на сайте, Messenger и Instagram, в другое приложение сразу после того, как лид получен: в вашу CRM, Zapier, Make, n8n или ваш собственный код. KnowStack делает подписанный HTTPS-запрос POST с контактами лида и перепиской на этот момент.
Вебхуки для лидов входят в Business, Enterprise и бесплатный пробный период. Настроить их можно, если ваша роль позволяет управлять пользователями, например Company Admin.
Как добавить вебхук
- Скопируйте адрес вебхука в приложении, которое должно получать лиды. Он должен начинаться с https://.
- В KnowStack откройте «Настройки», выберите «Интеграции» и перейдите к блоку «Отправка лидов в CRM».
- В разделе «Добавить вебхук» впишите в поле «Название» имя, которое легко узнать, вставьте адрес в поле «Адрес вебхука» и нажмите «Добавить вебхук».
- Скопируйте появившийся ключ подписи. Он начинается с whsec_ и показывается только один раз. Затем нажмите «Я сохранил ключ».
- Откройте меню вебхука и нажмите «Отправить тест». Результат появится сразу, а также в разделе «Журнал отправок».
Отправляются только лиды, полученные после добавления вебхука; более ранние остаются в KnowStack. Можно добавить несколько вебхуков, и каждый новый лид уходит во все активные.
Адрес должен быть публичным: только https, стандартный порт, без имени пользователя и пароля. Адреса в частной или локальной сети отклоняются, в том числе если публичное имя позже начнёт указывать на такую сеть. Перенаправления не выполняются, поэтому вставьте конечный адрес.
Когда отправляются запросы
| Событие | Когда | Что содержит |
|---|---|---|
| lead.created | Чат получает новый лид | Лид и переписка на этот момент |
| lead.updated | Имя, email или телефон появляются позже в том же лиде | Текущие данные лида и список changed с новыми полями, без переписки |
| test | Вы нажимаете «Отправить тест» | Пример лида с id 0 и короткий пример переписки |
Сообщения, написанные после создания лида, не отправляются никогда. Запрос lead.updated уходит только после того, как lead.created был принят, и только если поле из пустого стало заполненным.
Заголовки запроса
| Заголовок | Значение |
|---|---|
| Content-Type | application/json |
| User-Agent | LeadWebhook/1.0 |
| X-Webhook-Event | lead.created, lead.updated или test |
| X-Webhook-Delivery | Идентификатор отправки. При повторной попытке той же отправки он не меняется, поэтому используйте его, чтобы отсеивать дубликаты |
| X-Webhook-Timestamp | Время подписи в секундах Unix |
| X-Webhook-Signature | v1= и HMAC-SHA256 в шестнадцатеричном виде от метки времени, точки и исходного тела запроса, вычисленный с вашим ключом подписи |
Тело запроса (версия 1)
Тело запроса — JSON в UTF-8. Оно отправляется без переносов строк, а здесь показано отформатированным. Значения в угловых скобках заменяются вашими: название продукта — KnowStack, адрес — тот, по которому вы входите в систему. Запрос lead.created:
{
"version": 1,
"event": "lead.created",
"deliveryId": "4821",
"occurredAt": "2026-01-15T10:03:12.000Z",
"lead": {
"id": 1375,
"name": "Anna Novak",
"email": "[email protected]",
"phone": null,
"channel": "web_chat",
"channelLabel": "Website chat",
"source": "<product name> · Website chat",
"question": "Do you have availability next week?",
"firstPageUrl": "https://example.com/pricing",
"locale": "en",
"capturedAt": "2026-01-15T10:02:40.000Z",
"conversationUrl": "https://<your app address>/dashboard/channels/website-chat?conversation=812"
},
"transcript": [
{ "from": "customer", "text": "Hi, do you have availability next week?", "at": "2026-01-15T10:00:05.000Z" },
{ "from": "ai", "text": "Yes, we do. Could I take your email so the team can confirm a time?", "at": "2026-01-15T10:00:09.000Z" },
{ "from": "customer", "text": "Sure, [email protected]", "at": "2026-01-15T10:02:40.000Z" }
],
"transcriptIncomplete": false
}
| Поле | Значение |
|---|---|
| version | В этом формате всегда 1. Изменение, которое может сломать ваш код, получит новый номер |
| event, deliveryId | Те же значения, что в заголовках X-Webhook-Event и X-Webhook-Delivery |
| occurredAt | Время формирования запроса в формате ISO 8601 (UTC) |
| lead.id | Идентификатор лида в KnowStack. В lead.updated приходит тот же идентификатор, так что вы найдёте созданную запись |
| lead.name, lead.email, lead.phone | Контактные данные. Любое из полей может быть null |
| lead.channel | Где шёл чат: сейчас web_chat, messenger или instagram. С новыми каналами появятся новые значения, поэтому принимайте любой текст |
| lead.channelLabel, lead.source | Отображаемое название канала и готовый источник лида вида "KnowStack · Instagram" на языке того, кто добавил вебхук |
| lead.question | Вопрос, который клиент задал, когда был получен лид, или null |
| lead.firstPageUrl, lead.locale | Страница, с которой начался чат на сайте, и язык посетителя. Для других каналов обычно null |
| lead.capturedAt | Когда были оставлены контакты |
| lead.conversationUrl | Ссылка на переписку в KnowStack для тех, кто может войти в вашу компанию |
| transcript | Переписка до момента создания лида, от старых сообщений к новым, не больше 500 сообщений. У каждого есть from (customer, ai или team), text и at |
| transcriptIncomplete | true, если старые сообщения уже удалены по вашим настройкам хранения. У таких сообщений text равен null, а purged равен true |
Тело lead.updated содержит те же поля version, event, deliveryId, occurredAt и lead с текущими значениями лида. Вместо переписки в нём есть changed — список полей, заполненных после прошлого запроса, например ["phone"].
Проверка подписи
- Прочитайте исходное тело запроса до разбора JSON.
- Соедините значение X-Webhook-Timestamp, точку и исходное тело.
- Вычислите HMAC-SHA256 этого текста с вашим ключом подписи (полным значением вместе с whsec_) и запишите его в шестнадцатеричном виде.
- Сравните v1= с этим значением и заголовок X-Webhook-Signature сравнением за постоянное время.
- Отклоните запрос, если метка времени расходится с вашими часами больше чем на 5 минут. Так старый запрос нельзя будет отправить повторно.
Пример для Node.js с Express:
const crypto = require('crypto');
const express = require('express');
const SECRET = process.env.LEAD_WEBHOOK_SECRET; // whsec_...
const app = express();
// Keep the body raw: the signature covers the exact bytes that were sent.
app.post('/leads', express.raw({ type: 'application/json' }), (req, res) => {
const timestamp = req.get('X-Webhook-Timestamp') || '';
const received = req.get('X-Webhook-Signature') || '';
const expected = 'v1=' + crypto
.createHmac('sha256', SECRET)
.update(timestamp + '.' + req.body)
.digest('hex');
const fresh = Math.abs(Date.now() / 1000 - Number(timestamp)) <= 300;
const valid = received.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(received), Buffer.from(expected));
if (!fresh || !valid) return res.status(401).end();
const body = JSON.parse(req.body);
// req.get('X-Webhook-Delivery') identifies the delivery: skip it if you
// have already handled it.
console.log(body.event, body.lead.id);
res.status(204).end();
});
app.listen(3000);
Для проверки кода: ключ whsec_test, метка времени 1761559200 и тело {"a":1} дают подпись v1=ed347bcd87edf5b36afc10e41346740621d7f3c26b13ee1a4cc1eb7cddd0786f.
Ответы и повторные попытки
| Ваш ответ | Что происходит |
|---|---|
| 2xx | Доставлено |
| 408, 429, 5xx, тайм-аут или сетевая ошибка | Повторные попытки с растущими интервалами примерно 24 часа, затем отметка «ошибка». Retry-After в ответе 429 учитывается, но не больше часа |
| 410 | Вебхук сразу получает статус «Требует внимания» |
| 401, 403 или 404 три раза без успешной доставки между ними | Вебхук получает статус «Требует внимания» |
| Любой другой код, включая перенаправление | Отметка «ошибка» без повторных попыток |
Отвечайте в течение 10 секунд, иначе попытка считается тайм-аутом. Читаются только первые 64 КБ вашего ответа. Сначала ответьте, а долгую обработку выполняйте потом.
Если вебхук требует внимания
Пока у вебхука статус «Требует внимания» или «На паузе», новые лиды ждут в очереди и не теряются. Когда вебхук перестаёт работать, те, кто управляет пользователями, получают одно уведомление в колокольчике, а также в Telegram, если он подключён. Исправьте принимающее приложение или адрес через «Изменить» либо нажмите «Возобновить», если адрес был верным. Отправка продолжится, начиная с лидов, которые ждали.
«Журнал отправок» в меню вебхука показывает последние 50 запросов с результатом и кодом ответа. Нажмите «Повторить» у неудачного, чтобы отправить его ещё раз с тем же идентификатором отправки. На вкладке «Лиды» каждого чат-канала отметка показывает, дошёл ли лид до CRM; для неотправленного лида выберите «Отправить в CRM ещё раз» в меню его строки. Если лиды продолжают не доходить, а вебхук остаётся активным, в его строке появляется «Последние отправки не прошли», а те, кто управляет пользователями, получают уведомление, не чаще раза в день.
Ключ подписи
Если ключ утёк, выберите «Новый ключ подписи» в меню вебхука. Старый ключ сразу перестаёт работать, поэтому сразу же укажите новый в принимающем приложении.
Если ваша компания перейдёт на тариф без вебхуков для лидов, новые лиды не отправляются. Лиды, пришедшие в это время для активного вебхука, пропускаются и сами не отправятся после повышения тарифа; после повышения каждый из них можно отправить через «Отправить в CRM ещё раз». Лиды, ожидающие у приостановленного вебхука или у вебхука со статусом «Требует внимания», остаются в очереди и уйдут, когда вы повысите тариф и возобновите вебхук. Ваши вебхуки остаются в списке, и их по-прежнему можно приостановить или удалить.