Вебхуки: события на ваш сервер
Подписанные вебхуки и REST hooks reactive.chat: события, заголовки, тело, проверка HMAC-SHA256, повторы, тайм-ауты, отключение и примеры проверки на PHP, Node и Python.
Вебхуки сообщают серверу, что происходит в чате: новый разговор, новое сообщение, передача команде, оценка. Есть два способа:
- Подписанный вебхук — один целевой адрес на рабочее пространство, настраивается в аккаунте, каждая доставка подписана HMAC-SHA256. Подходящий вариант для собственных систем.
- REST hooks — цели, на которые инструмент автоматизации (Zapier, Make, n8n) сам подписывается и отписывается через серверный API.
События
- conversation.created — создан разговор. Канал в
channel(web,whatsapp,email…). - message.created — сохранено сообщение (от посетителя, ассистента, оператора или системы).
- handoff.requested — разговор нужно передать человеку; с
reasonиtarget. - csat.submitted — посетитель поставил оценку;
score(1или-1) иcomment(с замаскированными персональными данными). - fehlerfall.erstellt — на сайте обнаружен новый случай ошибки JavaScript (см. Руководство).
Разговоры из поиска по сайту (Smart Answer) вызывают события, только когда становятся видны как чат.
Настройка подписанного вебхука
В аккаунте в Настройки → Интеграции → Вебхуки (право: управление интеграциями):
- URL —
https://, не более 1000 символов, публично доступный. Один адрес на рабочее пространство. - События — выбор; ничего не выбрано означает все.
- Секрет подписи — показан на странице (64 шестнадцатеричных символа). Создать заново делает предыдущий недействительным немедленно; спланируйте переход так, чтобы получатель ненадолго принимал оба.
При сохранении тестовый вызов не отправляется. После включения до начала поступления событий может пройти около 15 секунд; события до включения задним числом не доставляются.
Доставка
POST /rc-webhook HTTP/1.1
Host: hooks.your-company.com
Content-Type: application/json; charset=utf-8
User-Agent: reactive.chat-webhook/1.0
X-RC-Event: csat.submitted
X-RC-Delivery: 01JAB3C4D5E6F7G8H9JKMNPQRS
X-RC-Timestamp: 1792503600
X-RC-Signature: sha256=3f0a1c...
{"id":"01JAB3C4D5E6F7G8H9JKMNPQRS","event":"csat.submitted","ts":1792503600,"site_key":"ABCDEFGHJKLMNPQRSTUVWX12","conversation_id":"01JAB2...","session_id":"s_...","visitor_id":"v_...","data":{"score":5,"comment":"Very helpful"}}
Заголовки:
- X-RC-Event — имя события.
- X-RC-Delivery — ID доставки; не меняется при повторах. Используйте его для распознавания дубликатов.
- X-RC-Timestamp — время Unix в секундах.
- X-RC-Signature —
sha256=+hex(HMAC_SHA256(secret, X-RC-Timestamp + "." + raw_body)). Ключ — сама показанная шестнадцатеричная строка.
Тело:
- id (строка) — то же, что
X-RC-Delivery. - event (строка).
- ts (целое число) — время Unix в секундах.
- site_key, conversation_id, session_id, visitor_id (строка или
null). - data (объект) — данные конкретного события. Для
fehlerfall.erstellt:fall_id,project_id,signatur,meldung,datei,zeile,spalte,seite,browser,os,stack,erste_ms,url(ссылка на случай в аккаунте). Дляmessage.created:messageсid,seq,kind,direction,author_type,author_name(только для оператора и ассистента),via,body(маскируется на сервере),redacted,ts(миллисекунды). Дляhandoff.requested:reasonиtarget. Дляcsat.submitted:scoreиcomment. Дляconversation.created:channel.
Проверка подписи
Проверяйте до любой обработки: время не старше 300 секунд, подпись по сырому телу, сравнение с постоянным временем.
PHP:
<?php
$geheim = getenv('RC_WEBHOOK_SECRET');
$body = file_get_contents('php://input');
$ts = $_SERVER['HTTP_X_RC_TIMESTAMP'] ?? '';
$sig = $_SERVER['HTTP_X_RC_SIGNATURE'] ?? '';
if (!ctype_digit($ts) || abs(time() - (int) $ts) > 300) { http_response_code(401); exit; }
$soll = 'sha256=' . hash_hmac('sha256', $ts . '.' . $body, $geheim);
if (!hash_equals($soll, $sig)) { http_response_code(401); exit; }
$ereignis = json_decode($body, true);
// detect duplicates: remember $ereignis['id']
http_response_code(204);
Node.js (Express):
const crypto = require('crypto');
app.post('/rc-webhook', express.raw({ type: 'application/json' }), (req, res) => {
const ts = req.get('X-RC-Timestamp') || '';
const sig = req.get('X-RC-Signature') || '';
if (!/^\d+$/.test(ts) || Math.abs(Date.now() / 1000 - Number(ts)) > 300) return res.sendStatus(401);
const soll = 'sha256=' + crypto.createHmac('sha256', process.env.RC_WEBHOOK_SECRET)
.update(ts + '.' + req.body.toString('utf8')).digest('hex');
if (sig.length !== soll.length || !crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(soll))) {
return res.sendStatus(401);
}
const ereignis = JSON.parse(req.body.toString('utf8'));
res.sendStatus(204);
verarbeiteSpaeter(ereignis); // respond quickly, work afterwards
});
Python (Flask):
import hmac, hashlib, os, time
from flask import request, abort
@app.post("/rc-webhook")
def rc_webhook():
ts = request.headers.get("X-RC-Timestamp", "")
sig = request.headers.get("X-RC-Signature", "")
body = request.get_data() # raw bytes
if not ts.isdigit() or abs(time.time() - int(ts)) > 300:
abort(401)
soll = "sha256=" + hmac.new(os.environ["RC_WEBHOOK_SECRET"].encode(),
ts.encode() + b"." + body, hashlib.sha256).hexdigest()
if not hmac.compare_digest(soll, sig):
abort(401)
return "", 204
Ответы, повторы, отключение
Быстро отвечайте кодом 2xx, а обработку выполняйте после. Тайм-ауты: 4 секунды на установление соединения, 10 секунд всего. Перенаправления не выполняются.
- 2xx — доставлено.
- 408, 429, 5xx, тайм-аут, ошибка сети — повтор через 1 с, 5 с, 25 с, 125 с и 625 с (всего до шести попыток), затем отбрасывается.
- 410 Gone — интеграция отключается. Используйте 410, только если действительно больше не хотите получать вебхуки.
- Другие 4xx — без повтора.
События старше часа больше не доставляются. Если ошибки накапливаются (5 за 60 секунд), доставка на вашу цель приостанавливается на 30 секунд; затем задания повторяются. Чат никогда не ждёт вебхук.
Порядок доставок не гарантируется. При необходимости сортируйте по ts или seq сообщений из API.
REST hooks (Zapier, Make, n8n)
Инструменты автоматизации сами подписывают свои цели через серверный API. Этим можно пользоваться и напрямую:
curl -X POST https://reactive.chat/v1/hooks \
-H "Authorization: Bearer rc_live_..." \
-H "Content-Type: application/json" \
-d '{"event":"message.created","target_url":"https://hooks.your-company.com/rc","source":"n8n"}'
- POST /v1/hooks — область прав с записью.
event(одно из событий выше),target_url(https://, не более 500 символов, публичный),source(zapier,makeилиn8n, по умолчаниюzapier). Ответ 201 сid. Одинаковое сочетание события и цели не создаётся дважды. Не более 200 подписок на рабочее пространство. - GET /v1/hooks — список с
id,event,target_url,source,failures,created_at,last_ok_at. - DELETE /v1/hooks/{id} — отписка.
Доставка REST hook:
POST https://hooks.your-company.com/rc
Content-Type: application/json
User-Agent: reactive.chat-n8n/1.0
X-RC-Event: message.created
X-RC-Delivery: 01JAB3...
{"event":"message.created","delivery_id":"01JAB3...","data":{"name":"message.created","ts":1792503600123,"site_key":"...","conversation_id":"...","session_id":"...","visitor_id":"...","message":{"id":"...","seq":7,"kind":"text","direction":"in","author_type":"bot","author_name":"Assistant","via":null,"body":"…","redacted":false,"ts":1792503600120}}}
- Без подписи. Используйте целевой адрес, который трудно угадать, и проверяйте
X-RC-Deliveryна дубликаты. Для собственных систем лучше подходит подписанный вебхук. data— полное событие: дополнительноworkspace_id,delivery_idиattempt(номер попытки). Здесьdata.tsуказано в миллисекундах.dataсобытияmessage.createdсодержитmessageсid,seq,kind,direction,author_type,author_name(только для оператора и ассистента),via,body(маскируется на сервере),redacted,ts.handoff.requestedсодержитreasonиtarget,csat.submitted—scoreиcomment,conversation.created—channel.- 410 отменяет только эту одну подписку. Хуки отозванного API-ключа больше не обслуживаются.
- В текущем состоянии доставка требует, чтобы соответствующая интеграция (Zapier, Make или n8n) была включена в рабочем пространстве в разделе Интеграции.
Чего нет
- Нет входящего вебхука для добавления сервером сообщений посетителя в разговор. Ответы от имени команды отправляются через серверный API или MCP.
- Нет переходного периода при обновлении секрета подписи.
- Нет события при удалении разговора.
Далее: Серверный API
Обновлено: