Webhooks : événements vers votre serveur
Webhooks signés et hooks REST de reactive.chat : événements, en-têtes, corps, vérification de signature HMAC-SHA256, nouvelles tentatives, délais, désactivation et exemples de vérification en PHP, Node et Python.
Les webhooks informent votre serveur de ce qui se passe dans le chat : nouvelle conversation, nouveau message, transfert à l’équipe, évaluation. Deux possibilités existent :
- Webhook signé – une adresse cible par espace de travail, configurée dans votre compte, chaque livraison étant signée avec HMAC-SHA256. La solution adaptée à vos propres systèmes.
- Hooks REST – des cibles auxquelles un outil d’automatisation (Zapier, Make, n8n) s’abonne et se désabonne lui-même via l’API serveur.
Événements
- conversation.created – une conversation a été créée. Canal dans
channel(web,whatsapp,email…). - message.created – un message a été enregistré (du visiteur, de l’assistant, d’un agent ou du système).
- handoff.requested – la conversation doit être transférée à un humain ; avec
reasonettarget. - csat.submitted – le visiteur a donné une évaluation ;
score(1ou-1) etcomment(avec masquage des données personnelles). - fehlerfall.erstellt – un nouveau cas d’erreur JavaScript a été détecté sur votre site (voir Manuel).
Les conversations issues de la recherche sur le site (Smart Answer) ne déclenchent des événements qu’une fois visibles sous forme de chat.
Configurer le webhook signé
Dans votre compte sous Paramètres → Intégrations → Webhooks (autorisation : gérer les intégrations) :
- URL –
https://, au maximum 1000 caractères, accessible publiquement. Une adresse par espace de travail. - Événements – une sélection ; aucune sélection signifie tous.
- Secret de signature – affiché sur la page (64 caractères hexadécimaux). Régénérer invalide l’ancien immédiatement ; prévoyez donc la transition pour que votre récepteur accepte brièvement les deux.
Aucun appel de test n’est envoyé à l’enregistrement. Après l’activation, il peut s’écouler environ 15 secondes avant que les événements soient transmis ; les événements antérieurs à l’activation ne sont pas livrés rétroactivement.
La livraison
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"}}
En-têtes :
- X-RC-Event – nom de l’événement.
- X-RC-Delivery – identifiant de la livraison ; reste identique lors des nouvelles tentatives. Utilisez-le pour détecter les doublons.
- X-RC-Timestamp – secondes Unix.
- X-RC-Signature –
sha256=+hex(HMAC_SHA256(secret, X-RC-Timestamp + "." + raw_body)). La clé est la chaîne hexadécimale affichée elle-même.
Corps :
- id (chaîne) – identique à
X-RC-Delivery. - event (chaîne).
- ts (entier) – secondes Unix.
- site_key, conversation_id, session_id, visitor_id (chaîne ou
null). - data (objet) – données propres à l’événement. Pour
fehlerfall.erstellt:fall_id,project_id,signatur,meldung,datei,zeile,spalte,seite,browser,os,stack,erste_ms,url(lien vers le cas dans votre compte). Pourmessage.created:messageavecid,seq,kind,direction,author_type,author_name(uniquement pour l’agent et l’assistant),via,body(masqué sur le serveur),redacted,ts(millisecondes). Pourhandoff.requested:reasonettarget. Pourcsat.submitted:scoreetcomment. Pourconversation.created:channel.
Vérifier la signature
Vérifiez avant tout traitement : horodatage datant d’au maximum 300 secondes, signature sur le corps brut, comparaison en temps constant.
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
Réponses, nouvelles tentatives, désactivation
Répondez rapidement avec un code 2xx, puis traitez les données. Délais : 4 secondes pour établir la connexion, 10 secondes au total. Les redirections ne sont pas suivies.
- 2xx – livré.
- 408, 429, 5xx, dépassement de délai, erreur réseau – nouvelle tentative après 1 s, 5 s, 25 s, 125 s et 625 s (jusqu’à six tentatives au total), puis abandon.
- 410 Gone – l’intégration est désactivée. Utilisez 410 uniquement si vous ne souhaitez vraiment plus recevoir de webhooks.
- autres 4xx – aucune nouvelle tentative.
Les événements datant de plus d’une heure ne sont plus livrés. Si les erreurs s’accumulent (5 en 60 secondes), la livraison vers votre cible est suspendue pendant 30 secondes ; les tâches font ensuite l’objet de nouvelles tentatives. Un chat n’attend jamais votre webhook.
L’ordre des livraisons n’est pas garanti. Au besoin, triez par ts ou par le seq des messages provenant de l’API.
Hooks REST (Zapier, Make, n8n)
Les outils d’automatisation abonnent eux-mêmes leurs cibles via l’API serveur. Vous pouvez aussi utiliser cette possibilité directement :
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 – une portée avec autorisation d’écriture.
event(l’un des événements ci-dessus),target_url(https://, au maximum 500 caractères, public),source(zapier,makeoun8n, par défautzapier). Réponse 201 avecid. La même combinaison d’événement et de cible n’est pas créée deux fois. Au maximum 200 abonnements par espace de travail. - GET /v1/hooks – liste avec
id,event,target_url,source,failures,created_at,last_ok_at. - DELETE /v1/hooks/{id} – se désabonner.
Livraison d’un hook REST :
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}}}
- Non signé. Utilisez une adresse cible difficile à deviner et vérifiez
X-RC-Deliverypour détecter les doublons. Pour vos propres systèmes, le webhook signé est la solution préférable. dataest l’événement complet : avec, en plus,workspace_id,delivery_idetattempt(nombre de tentatives). Ici,data.tsest en millisecondes.- Le
datademessage.createdcontientmessageavecid,seq,kind,direction,author_type,author_name(uniquement pour l’agent et l’assistant),via,body(masqué côté serveur),redacted,ts.handoff.requestedcontientreasonettarget,csat.submittedcontientscoreetcomment,conversation.createdcontientchannel. - Un 410 ne supprime que cet abonnement. Les hooks d’une clé d’API révoquée ne sont plus livrés.
- Dans l’état actuel, la livraison exige que l’intégration correspondante (Zapier, Make ou n8n) soit activée dans l’espace de travail sous Intégrations.
Ce qui n’existe pas
- Aucun webhook entrant permettant à votre serveur d’injecter des messages de visiteurs dans une conversation. Vous envoyez des réponses au nom de votre équipe via l’API serveur ou MCP.
- Aucune période de transition lors du renouvellement du secret de signature.
- Aucun événement lors de la suppression d’une conversation.
Suite : API serveur
Dernière mise à jour: