Webhooky: události na váš server
Podepsané webhooky a REST hooky z reactive.chat: události, hlavičky, tělo, ověření podpisu HMAC-SHA256, opakování, časové limity, deaktivace a příklady ověření v PHP, Node a Pythonu.
Webhooky vašemu serveru hlásí, co se děje v chatu: nová konverzace, nová zpráva, předání týmu, hodnocení. Existují dvě cesty:
- Podepsaný webhook – jedna cílová adresa na pracovní prostor, nastavená v účtu, každé doručení podepsané HMAC-SHA256. Správná cesta pro vlastní systémy.
- REST hooky – cíle, které si automatizační nástroj (Zapier, Make, n8n) sám přihlašuje a odhlašuje přes serverové API.
Události
- conversation.created – byla vytvořena konverzace. Kanál v
channel(web,whatsapp,email…). - message.created – byla uložena zpráva (od návštěvníka, asistenta, operátora nebo systému).
- handoff.requested – konverzace má přejít k člověku; s
reasonatarget. - csat.submitted – návštěvník udělil hodnocení;
score(1nebo-1) acomment(s maskovanými osobními údaji). - fehlerfall.erstellt – na vašem webu byl rozpoznán nový chybový případ JavaScriptu (viz Příručka).
Konverzace z vyhledávání na webu (Smart Answer) vyvolávají události až poté, co se stanou viditelnými jako chat.
Nastavení podepsaného webhooku
V účtu pod Nastavení → Integrace → Webhooky (oprávnění: spravovat integrace):
- URL –
https://, nejvýše 1000 znaků, veřejně dostupné. Jedna adresa na pracovní prostor. - Události – výběr; žádný výběr znamená vše.
- Tajný podpisový klíč – zobrazuje se na stránce (64 hexadecimálních znaků). Vygenerovat znovu předchozí klíč zneplatní okamžitě; naplánujte změnu tak, aby příjemce krátce přijímal oba.
Při uložení se neodesílá testovací volání. Po zapnutí může trvat přibližně 15 sekund, než začnou události proudit; události z doby před zapnutím se zpětně nedoručují.
Doručení
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"}}
Hlavičky:
- X-RC-Event – název události.
- X-RC-Delivery – ID doručení; při opakování zůstává stejné. Použijte ho k rozpoznání duplicit.
- X-RC-Timestamp – Unixové sekundy.
- X-RC-Signature –
sha256=+hex(HMAC_SHA256(secret, X-RC-Timestamp + "." + raw_body)). Klíčem je samotný zobrazený hexadecimální řetězec.
Tělo:
- id (řetězec) – stejné jako
X-RC-Delivery. - event (řetězec).
- ts (celé číslo) – Unixové sekundy.
- site_key, conversation_id, session_id, visitor_id (řetězec nebo
null). - data (objekt) – data konkrétní události. Pro
fehlerfall.erstellt:fall_id,project_id,signatur,meldung,datei,zeile,spalte,seite,browser,os,stack,erste_ms,url(odkaz na případ v účtu). Promessage.created:messagesid,seq,kind,direction,author_type,author_name(jen u operátora a asistenta),via,body(maskované na serveru),redacted,ts(milisekundy). Prohandoff.requested:reasonatarget. Procsat.submitted:scoreacomment. Proconversation.created:channel.
Ověření podpisu
Ověřujte před jakýmkoli zpracováním: časové razítko nejvýše 300 sekund staré, podpis nad surovým tělem, porovnání v konstantním čase.
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
Odpovědi, opakování, deaktivace
Odpovězte rychle kódem 2xx a zpracovávejte potom. Časové limity: 4 sekundy pro navázání spojení, celkem 10 sekund. Přesměrování se nenásledují.
- 2xx – doručeno.
- 408, 429, 5xx, časový limit, chyba sítě – opakování po 1 s, 5 s, 25 s, 125 s a 625 s (celkem nejvýše šest pokusů), potom zahození.
- 410 Gone – integrace se deaktivuje. Použijte 410 pouze tehdy, když opravdu nechcete další webhooky.
- ostatní 4xx – bez opakování.
Události starší než hodinu se už nedoručují. Pokud se chyby nahromadí (5 za 60 sekund), doručování na cíl se pozastaví na 30 sekund; úlohy se poté zkusí znovu. Chat na webhook nikdy nečeká.
Pořadí doručení není zaručeno. V případě potřeby řaďte podle ts nebo seq zpráv z API.
REST hooky (Zapier, Make, n8n)
Automatizační nástroje přihlašují cíle samy přes serverové API. Můžete to použít i přímo:
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 – rozsah s oprávněním zápisu.
event(jedna z událostí výše),target_url(https://, nejvýše 500 znaků, veřejná),source(zapier,makenebon8n, výchozízapier). Odpověď 201 sid. Stejná kombinace události a cíle se nevytvoří dvakrát. Nejvýše 200 odběrů na pracovní prostor. - GET /v1/hooks – seznam s
id,event,target_url,source,failures,created_at,last_ok_at. - DELETE /v1/hooks/{id} – odhlášení.
Doručení REST hooku:
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}}}
- Nepodepsané. Použijte obtížně uhodnutelnou cílovou adresu a kontrolujte duplicity přes
X-RC-Delivery. Pro vlastní systémy je lepší podepsaný webhook. dataje úplná událost: navícworkspace_id,delivery_idaattempt(počet pokusů).data.tsje zde v milisekundách.dataumessage.createdobsahujemessagesid,seq,kind,direction,author_type,author_name(jen u operátora a asistenta),via,body(maskované na serveru),redacted,ts.handoff.requestednesereasonatarget,csat.submittedscoreacomment,conversation.createdchannel.- 410 odhlásí jen tento jeden odběr. Hooky odvolaného klíče API se už neobsluhují.
- V aktuálním stavu doručování vyžaduje, aby byla odpovídající integrace (Zapier, Make nebo n8n) zapnutá v pracovním prostoru pod Integrace.
Co neexistuje
- Žádný příchozí webhook, kterým by váš server vkládal do konverzace zprávy návštěvníků. Odpovědi jménem týmu odesíláte přes serverové API nebo MCP.
- Žádné přechodné období při obnově tajného podpisového klíče.
- Žádná událost při smazání konverzace.
Dále: Serverové API
చివరిగా నవీకరించినది: