DOCUMENTS/Webhooks~ 8 MIN DE LECTURE

EVENTS · HMAC · POST

EasyLiveChat vous appelle
à l'instant où quelque chose se produit.

Les webhooks sont le canal push d'EasyLiveChat — au lieu d'interroger notre API selon un planning, vous nous donnez une URL et nous y POSTons chaque événement pertinent dans la seconde qui suit. Chaque requête est signée en HMAC-SHA256 pour que votre serveur puisse prouver qu'elle vient bien de nous.

§ 00Ce que sont les webhooks

Quand quelque chose se produit côté EasyLiveChat — un client écrit dans votre widget, un agent ferme une conversation, une action liée à l'audit a lieu — nous faisons un POST HTTPS sortant vers chaque URL que vous avez enregistrée. Le corps est en JSON et contient l'intégralité du payload, pour que votre serveur réagisse sans polling.

Voyez ça comme l'image miroir de l'API REST. L'API permet à votre code d'atteindre EasyLiveChat. Les webhooks permettent à EasyLiveChat d'atteindre votre code. La plupart des intégrations utilisent les deux.

Chaque endpoint enregistré a son propre secret. Nous signons chaque corps de requête en HMAC-SHA256 avec ce secret et envoyons le digest hex dans l'en-tête x-easylivechat-signature. Votre serveur recalcule le HMAC avec le même secret et compare — concordance signifie que la requête vient bien de nous, non-concordance signifie la rejeter.

§ 01Disponibilité par plan

Les endpoints webhook peuvent être créés sur tous les plans payants et pendant l'essai gratuit de 14 jours. Pas de facturation à l'événement — la diffusion vers plusieurs endpoints est incluse.

Le flux audit.event est réservé à Enterprise, conditionné par l'entitlement auditWebhookExport. message.created et conversation.updated se déclenchent sur tout plan permettant l'accès à l'API.

§ 02Configurer un endpoint

Ajoutez un endpoint depuis https://app.livechattools.com/settings/webhooks. Nous générerons un secret aléatoire par endpoint et vous le montrerons une seule fois à la création. Traitez-le comme un mot de passe — copiez-le immédiatement dans le coffre à secrets de votre serveur.

  • URLDoit être https:// et résoudre vers une IP publique. Nous refusons les adresses de loopback, privées et de métadonnées cloud à la création comme à la livraison.
  • ÉvénementsChoisissez des noms d'événements spécifiques ou abonnez-vous à * (tous les événements). Les wildcards sont pratiques pour les prototypes, mais des listes plus restreintes rendent votre handler plus simple à raisonner.
  • SecretGénéré automatiquement, affiché une fois. Sert à signer chaque livraison. Si vous le perdez, supprimez l'endpoint et créez-en un nouveau — pas de récupération.

Actif par défaut. Vous pouvez révoquer un endpoint à tout moment depuis la même page — les livraisons s'arrêtent instantanément.

§ 03Forme du payload

Chaque livraison est un POST avec content-type: application/json. Les en-têtes identifient l'événement et portent la signature ; l'enveloppe du corps est toujours { event, deliveredAt, data } :

POST https://your-server.example.com/webhook
content-type: application/json
user-agent: EasyLiveChat-Webhooks/1.0
x-easylivechat-event: message.created
x-easylivechat-signature: sha256=<hex>

{
  "event": "message.created",
  "deliveredAt": "2026-05-27T08:55:25.841Z",
  "data": {
    "conversationId": "cmp...",
    "message": {
      "id": "cmp...",
      "body": "Hi!",
      "senderType": "CUSTOMER",
      "createdAt": "2026-05-27T08:55:25.840Z"
    }
  }
}

event est la même valeur que l'en-tête x-easylivechat-event. La forme de data varie selon l'événement — voir le catalogue ci-dessous.

§ 04Vérifier la signature

Quiconque connaît l'URL de votre endpoint peut y POSTer n'importe quoi. La signature HMAC est la façon de distinguer nos requêtes des fausses. Recalculez-la avec votre secret et rejetez la requête en cas de non-concordance.

Lisez les octets bruts du corps (NE faites PAS json.parse d'abord — la re-sérialisation réordonnera les clés et cassera le hash). Retirez le préfixe sha256= de l'en-tête. Calculez HMAC-SHA256(rawBody, secret) et comparez en temps constant avec l'hex reçu.

Node.js

import crypto from 'node:crypto';
import express from 'express';

const SECRET = process.env.WEBHOOK_SECRET;
const app = express();
app.use(express.raw({ type: 'application/json' }));

app.post('/webhook', (req, res) => {
  const received = (req.header('x-easylivechat-signature') || '').replace(/^sha256=/, '');
  const expected = crypto.createHmac('sha256', SECRET).update(req.body).digest('hex');
  const ok =
    received.length === expected.length &&
    crypto.timingSafeEqual(Buffer.from(received, 'hex'), Buffer.from(expected, 'hex'));
  if (!ok) return res.status(401).send('bad signature');

  const event = JSON.parse(req.body.toString('utf8'));
  // handle event.event, event.data...
  res.status(200).send('ok');
});

Python (Flask)

import hmac, hashlib, os
from flask import Flask, request, abort

SECRET = os.environ["WEBHOOK_SECRET"].encode()
app = Flask(__name__)

@app.post("/webhook")
def webhook():
    received = request.headers.get("x-easylivechat-signature", "").removeprefix("sha256=")
    expected = hmac.new(SECRET, request.get_data(), hashlib.sha256).hexdigest()
    if not hmac.compare_digest(received, expected):
        abort(401)
    event = request.get_json()
    # handle event["event"], event["data"]...
    return "ok", 200

curl (debugging)

# Recompute the signature locally and compare with the header.
echo -n "$RAW_BODY" | openssl dgst -sha256 -hmac "$WEBHOOK_SECRET"

timingSafeEqual / hmac.compare_digestutilisez toujours une comparaison à temps constant pour que les attaquants ne puissent pas sonder le secret octet par octet.

§ 05Catalogue d'événements

Aujourd'hui la plateforme déclenche quatre types d'événements. Nous en ajouterons à mesure que les fonctionnalités sortent — abonnez-vous à * pour la compatibilité future.

ÉvénementSe déclenche quandForme des données
message.createdUn nouveau message arrive sur une conversation, peu importe l'expéditeur (client entrant, agent sortant, envoi par API REST).{ conversationId, message }
conversation.updatedLe statut d'une conversation (OPEN · SNOOZED · CLOSED) ou son assignedAgentId change.{ conversationId, status?, assignedAgentId? }
audit.eventChaque fois qu'une ligne d'audit-log est écrite — connexion d'agent, changement de rôle, intégration créée, clé révoquée, etc. (Plan Enterprise.){ action, entity, entityId, actorId, metadata }
webhook.testVous cliquez sur "Test" dans Paramètres → Webhooks. Signé et formé exactement comme un événement réel.{ tenantId, test: true }

Abonnez-vous à * pour recevoir tous les événements actuels et futurs. Abonnez-vous à des noms spécifiques si vous voulez restreindre ce que votre handler doit connaître.

§ 06Tester l'intégration

Le bouton "Test" dans Paramètres → Webhooks déclenche un événement webhook.test vers votre endpoint et rapporte le statut HTTP upstream et le temps écoulé. Utilisez-le pour valider votre handler avant d'y diriger du trafic réel.

Le payload de test utilise exactement la même enveloppe de corps, les mêmes noms d'en-tête et le même schéma HMAC que les événements de production — si votre vérification passe pour webhook.test, elle passera pour message.created et tout le reste.

§ 07Réessais et délais

Nous donnons 10 secondes à votre serveur pour répondre. Tout statut non-2xx ou erreur réseau est un échec. Les livraisons échouées sont retentées jusqu'à 5 fois avec backoff exponentiel à partir de 2 secondes, donc un endpoint instable a plusieurs chances avant que nous abandonnions cet événement.

Nous ne garantissons PAS une livraison exactly-once — sous flapping réseau, le même événement peut arriver deux fois. Rendez votre handler idempotent : dédupliquez sur data.message.id (ou l'identifiant pertinent pour cet événement).

§ 08Liste de sécurité

  • Utilisez toujours https:// — les endpoints http:// purs sont rejetés à la création.
  • Nous bloquons les IPs privées, loopback et cloud-metadata à la création comme à la livraison, donc un enregistrement DNS mal configuré ne peut pas servir à pivoter dans votre réseau.
  • Comparez les signatures avec un égal timing-safe (Node crypto.timingSafeEqual, Python hmac.compare_digest, Go hmac.Equal).
  • Tournez en supprimant l'endpoint et en créant un nouveau avec la même URL. Mettez à jour votre coffre à secrets de manière atomique.