ChatNeuron
Разделы

для разработчиков

Исходящие вебхуки

ChatNeuron отправляет POST на адрес вашей системы, когда появляется или меняется заявка, начинается, переходит к человеку или закрывается диалог с клиентом, — без опроса API.

Подключение

  • Владелец или администратор добавляет адрес в кабинете: Настройки → API и вебхуки → Исходящие вебхуки, и отмечает события.
  • Адрес — только https://, без логина и пароля в адресе. Адреса во внутренней сети не принимаются.
  • После добавления один раз показывается секрет whsec_… — им проверяется подпись. Сохраните его сразу.
  • Кнопка «Проверить» отправляет событие test. «Журнал» показывает доставки за 30 дней: тело, ответ вашего сервера, попытки — и отправляет событие снова. До 10 вебхуков на компанию.

События

eventКогда
lead.createdНовая заявка из любого канала или из API. Заявка, скрытая до оплаты тарифа, не отправляется.
lead.updatedУ заявки сменилась стадия или статус, поправили контакты: в кабинете, из CRM, после оплаты заказа.
dialog.startedКлиент начал новый диалог в любом канале. Тестовые диалоги не отправляются.
dialog.handed_offДиалог передан человеку: клиент попросил менеджера или AI-сотрудник позвал сотрудника.
dialog.closedДиалог закрыт: 24 часа тишины или новый разговор после передачи человеку.
message.createdНовая реплика клиента, AI-сотрудника или сотрудника компании. Событий много — подписывайтесь, если нужна переписка в реальном времени.
testПробная отправка из настроек.

Поля каждого события — в справочнике событий.

Запрос

Тело — JSON { id, event, createdAt, data }. id — id события, он же в заголовке X-ChatNeuron-Webhook-Id и одинаков во всех повторах: по нему отбрасывайте дубли. Номер попытки — в X-ChatNeuron-Delivery-Attempt. Пример lead.created:

POST /hooks/chatneuron HTTP/1.1
Content-Type: application/json
User-Agent: ChatNeuron-Webhooks/1
X-ChatNeuron-Event: lead.created
X-ChatNeuron-Webhook-Id: 8d0c7c1e-…
X-ChatNeuron-Delivery-Attempt: 1
X-ChatNeuron-Signature: t=1761556502,v1=5f2b…

{
  "id": "8d0c7c1e-…",
  "event": "lead.created",
  "createdAt": "2026-10-27T09:15:02.114Z",
  "data": {
    "id": "cmv…",
    "agentId": "cmu…",
    "name": "Анна",
    "phone": "+79991234567",
    "email": null,
    "message": "Нужна консультация по доставке",
    "type": null,
    "topic": "Доставка",
    "source": "chat",
    "score": 72,
    "createdAt": "2026-10-27T09:15:02.114Z"
  }
}

Пример dialog.started:

{
  "id": "1f4e…",
  "event": "dialog.started",
  "createdAt": "2026-10-27T09:12:40.003Z",
  "data": {
    "id": "cmv…",
    "agentId": "cmu…",
    "channel": "telegram",
    "topic": null,
    "startedAt": "2026-10-27T09:12:40.003Z"
  }
}

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

Заголовок X-ChatNeuron-Signature: t=<unix-время>,v1=<подпись>. Подпись — HMAC-SHA256 от строки <t>.<тело запроса> секретом вебхука, в hex. Считайте её от сырого тела, до разбора JSON, и отклоняйте запросы старше 5 минут.

Node.js

import { createHmac, timingSafeEqual } from "node:crypto"

// rawBody — тело запроса строкой, как пришло (до JSON.parse)
export function verifyChatNeuron(rawBody, header, secret, toleranceSec = 300) {
  const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")))
  const t = Number(parts.t)
  if (!t || Math.abs(Date.now() / 1000 - t) > toleranceSec) return false
  const expected = createHmac("sha256", secret).update(`${t}.${rawBody}`).digest("hex")
  const got = Buffer.from(parts.v1 ?? "", "hex")
  const want = Buffer.from(expected, "hex")
  return got.length === want.length && timingSafeEqual(got, want)
}

Python

import hashlib, hmac, time

def verify_chatneuron(raw_body: bytes, header: str, secret: str, tolerance: int = 300) -> bool:
    parts = dict(p.split("=", 1) for p in header.split(","))
    t = int(parts.get("t", 0))
    if not t or abs(time.time() - t) > tolerance:
        return False
    expected = hmac.new(secret.encode(), f"{t}.".encode() + raw_body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, parts.get("v1", ""))

Доставка

  • Успех — любой ответ 2xx за 8 секунд. Отвечайте сразу, а долгую обработку делайте в фоне.
  • Повторы: если адрес не ответил 2xx, повторим через 1, 5, 15 минут, 1, 3, 6 и 12 часов — всего 8 попыток за сутки. Доставка «как минимум один раз»: событие может прийти дважды, сверяйте id.
  • Если адрес не принимает события 3 дня подряд, вебхук выключается, а владельцу приходит уведомление. Включите его в настройках, когда адрес снова заработает.
  • Редиректы не выполняются. Пропущенное можно добрать из ленты событий GET /events — там те же события за 30 дней.