Webhooki: zdarzenia do twojego serwera
Podpisane webhooki i REST hooki reactive.chat – zdarzenia, nagłówki, treść, weryfikacja podpisu przez HMAC-SHA256, ponowienia, limity czasu, dezaktywacja i przykłady weryfikacji w PHP, Node i Pythonie.
Webhooki informują twój serwer, co dzieje się w czacie: nowa rozmowa, nowa wiadomość, przekazanie do zespołu, ocena. Są dwie drogi:
- Podpisany webhook – jeden adres docelowy na przestrzeń roboczą, skonfigurowany w koncie, każde dostarczenie podpisane HMAC-SHA256. Właściwa droga dla twoich własnych systemów.
- REST hooki – cele, które narzędzie automatyzacji (Zapier, Make, n8n) samo rejestruje i wyrejestrowuje przez API serwera.
Zdarzenia
- conversation.created – powstała rozmowa. Kanał w
channel(web,whatsapp,email…). - message.created – zapisano wiadomość (od odwiedzającego, asystenta, agenta lub systemu).
- handoff.requested – rozmowa ma trafić do człowieka; z
reasonitarget. - csat.submitted – odwiedzający wystawił ocenę;
score(1albo-1) icomment(z zamaskowanymi danymi osobowymi). - fehlerfall.erstellt – wykryto nowy przypadek błędu JavaScript na twojej stronie (zobacz Podręcznik).
Rozmowy z wyszukiwarki strony (Smart Answer) wyzwalają zdarzenia dopiero wtedy, gdy stają się widoczne jako czat.
Konfiguracja podpisanego webhooka
W koncie, w sekcji Ustawienia → Integracje → Webhooks (uprawnienie: zarządzanie integracjami):
- Adres docelowy (HTTPS) –
https://, najwyżej 1000 znaków, publicznie osiągalny. Jeden adres na przestrzeń roboczą. - Zdarzenia – wybór; brak wyboru oznacza wszystkie.
- Sekret podpisu – wyświetlany na stronie (64 znaki hex). Wygeneruj nowy unieważnia dotychczasowy od razu; zaplanuj więc zmianę tak, by twój odbiorca przez chwilę akceptował oba.
Przy zapisie nie jest wysyłane żadne wywołanie testowe. Po włączeniu może minąć do ok. 15 sekund, zanim zdarzenia zaczną płynąć; zdarzenia sprzed włączenia nie są dostarczane później.
Dostarczenie
POST /rc-webhook HTTP/1.1
Host: hooks.deine-firma.de
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":"Bardzo pomocne"}}
Nagłówki:
- X-RC-Event – nazwa zdarzenia.
- X-RC-Delivery – identyfikator dostarczenia; pozostaje ten sam przy ponowieniach. Używaj go do wykrywania duplikatów.
- X-RC-Timestamp – sekundy Unix.
- X-RC-Signature –
sha256=+hex(HMAC_SHA256(geheimnis, X-RC-Timestamp + "." + roher_body)). Kluczem jest sam wyświetlany ciąg hex.
Treść:
- id (String) – jak
X-RC-Delivery. - event (String).
- ts (liczba całkowita) – sekundy Unix.
- site_key, conversation_id, session_id, visitor_id (String albo
null). - data (obiekt) – dane zależne od zdarzenia. Przy
fehlerfall.erstellt:fall_id,project_id,signatur,meldung,datei,zeile,spalte,seite,browser,os,stack,erste_ms,url(link do przypadku w koncie). Przymessage.created:messagezid,seq,kind,direction,author_type,author_name(tylko przy agencie i asystencie),via,body(maskowane po stronie serwera),redacted,ts(milisekundy). Przyhandoff.requested:reasonitarget. Przycsat.submitted:scoreicomment. Przyconversation.created:channel.
Weryfikacja podpisu
Sprawdzaj przed jakimkolwiek przetwarzaniem: znacznik czasu najwyżej 300 sekund wstecz, podpis na surowej treści, porównanie w stałym czasie.
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);
// wykrywanie duplikatów: zapamiętaj $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); // odpowiedz szybko, przetwarzaj potem
});
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() # surowe bajty
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
Odpowiedzi, ponowienia, dezaktywacja
Odpowiadaj szybko kodem 2xx i przetwarzaj potem. Limity czasu: 4 sekundy na nawiązanie połączenia, 10 sekund łącznie. Przekierowania nie są obsługiwane.
- 2xx – dostarczone.
- 408, 429, 5xx, przekroczenie czasu, błąd sieci – ponowienie po 1 s, 5 s, 25 s, 125 s i 625 s (łącznie do sześciu prób), potem odrzucenie.
- 410 Gone – integracja zostaje dezaktywowana. Używaj 410 tylko wtedy, gdy naprawdę nie chcesz już webhooków.
- inne 4xx – bez ponowienia.
Zdarzenia starsze niż godzina nie są już dostarczane. Gdy błędy się mnożą (5 w ciągu 60 sekund), dostarczanie do twojego celu zostaje wstrzymane na 30 sekund; zadania są potem ponawiane. Czat nigdy nie czeka na twój webhook.
Kolejność dostarczeń nie jest gwarantowana. W razie potrzeby sortuj według ts lub według seq wiadomości z API.
REST hooki (Zapier, Make, n8n)
Narzędzia automatyzacji same rejestrują swoje cele przez API serwera. Możesz z tego korzystać także bezpośrednio:
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.deine-firma.de/rc","source":"n8n"}'
- POST /v1/hooks – zakres z prawem zapisu.
event(jedno ze zdarzeń powyżej),target_url(https://, najwyżej 500 znaków, publiczny),source(zapier,makealbon8n, domyślniezapier). Odpowiedź 201 zid. Ta sama kombinacja zdarzenia i celu nie jest tworzona dwa razy. Najwyżej 200 rejestracji na przestrzeń roboczą. - GET /v1/hooks – lista z
id,event,target_url,source,failures,created_at,last_ok_at. - DELETE /v1/hooks/{id} – wyrejestrowanie.
Dostarczenie REST hooka:
POST https://hooks.deine-firma.de/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":"Assistent","via":null,"body":"…","redacted":false,"ts":1792503600120}}}
- Niepodpisane. Używaj trudnego do odgadnięcia adresu docelowego i sprawdzaj
X-RC-Deliverypod kątem duplikatów. Dla własnych systemów lepszą drogą jest podpisany webhook. datato pełne zdarzenie: dodatkowoworkspace_id,delivery_idiattempt(licznik prób).data.tsjest tu w milisekundach.datazdarzeniamessage.createdzawieramessagezid,seq,kind,direction,author_type,author_name(tylko przy agencie i asystencie),via,body(zamaskowane po stronie serwera),redacted,ts.handoff.requestedzawierareasonitarget,csat.submitted–scoreicomment,conversation.created–channel.- 410 wyrejestrowuje tylko tę jedną rejestrację. Hooki unieważnionego klucza API nie są już obsługiwane.
- Według obecnego stanu dostarczenie wymaga, aby odpowiednia integracja (Zapier, Make lub n8n) była włączona w przestrzeni roboczej w sekcji Integracje.
Czego nie ma
- Przychodzącego webhooka, przez który twój serwer wprowadzałby wiadomości odwiedzających do rozmowy. Odpowiedzi w imieniu twojego zespołu wysyłasz przez API serwera albo MCP.
- Okresu przejściowego przy odnawianiu sekretu podpisu.
- Zdarzenia przy usunięciu rozmowy.
Dalej: API serwera
Paskutinį kartą atnaujinta: