§ 00Was Webhooks sind
Wenn auf der EasyLiveChat-Seite etwas passiert — ein Kunde schickt eine Nachricht in Ihr Widget, ein Agent schließt ein Gespräch, eine audit-relevante Aktion findet statt — senden wir einen ausgehenden HTTPS-POST an jede registrierte URL. Der Body ist JSON und enthält die vollständige Ereignis-Payload, sodass Ihr Server ohne Polling reagieren kann.
Stellen Sie es sich als Spiegelbild der REST-API vor. Die API ist für Code, den Sie kontrollieren und der in EasyLiveChat hineinreicht. Webhooks sind dafür, dass EasyLiveChat in Ihren Code hineinreicht. Die meisten Integrationen nutzen beides.
Jeder registrierte Endpunkt hat sein eigenes Geheimnis. Wir signieren jeden Request-Body mit HMAC-SHA256 unter Verwendung dieses Geheimnisses und senden den Hex-Digest im Header x-easylivechat-signature. Ihr Server berechnet das HMAC mit demselben Geheimnis nochmals und vergleicht — Übereinstimmung bedeutet, die Anfrage kam wirklich von uns, ein Mismatch bedeutet verwerfen.
§ 01Plan-Verfügbarkeit
Webhook-Endpunkte können in jedem kostenpflichtigen Plan und während der 14-tägigen Testphase erstellt werden. Es gibt keine Abrechnung pro Ereignis — die Fan-out-Verteilung auf mehrere Endpunkte ist enthalten.
Der audit.event-Stream ist nur Enterprise, gegated durch das auditWebhookExport-Entitlement. message.created und conversation.updated feuern in jedem Plan, der API-Zugriff erlaubt.
§ 02Endpunkt konfigurieren
Endpunkt hinzufügen unter https://app.livechattools.com/settings/webhooks. Wir generieren einen zufälligen Endpunkt-spezifischen Schlüssel und zeigen ihn Ihnen genau einmal bei der Erstellung. Behandeln Sie ihn wie ein Passwort — kopieren Sie ihn sofort in den Secret-Store Ihres Servers.
- URL — Muss https:// sein und auf eine öffentliche IP auflösen. Wir lehnen Loopback-, private und Cloud-Metadaten-Adressen sowohl bei der Erstellung als auch bei der Zustellung ab.
- Ereignisse — Wählen Sie entweder spezifische Ereignisnamen oder abonnieren Sie * (alle Ereignisse). Wildcards sind praktisch zum Prototyping, aber engere Ereignislisten machen Ihren Handler verständlicher.
- Geheimnis — Automatisch generiert, einmal angezeigt. Wird zum Signieren jeder Zustellung verwendet. Wenn Sie es verlieren, löschen Sie den Endpunkt und erstellen einen neuen — es gibt keinen Wiederherstellungspfad.
Standardmäßig aktiv. Sie können einen Endpunkt jederzeit von derselben Seite aus widerrufen — Zustellungen stoppen sofort.
§ 03Payload-Struktur
Jede Zustellung ist ein POST mit content-type: application/json. Header identifizieren das Ereignis und tragen die Signatur; der Body-Umschlag ist immer { 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 ist derselbe Wert wie der Header x-easylivechat-event. Die Form von data variiert je nach Ereignis — siehe Ereigniskatalog unten.
§ 04Signatur prüfen
Jeder, der Ihre Endpunkt-URL kennt, kann Schrott dorthin POSTen. Die HMAC-Signatur ist, wie Sie unsere Anfragen von gefälschten unterscheiden. Berechnen Sie sie mit Ihrem Geheimnis neu und lehnen Sie die Anfrage bei Mismatch ab.
Lesen Sie die rohen Body-Bytes (NICHT zuerst json.parse — erneutes Serialisieren ordnet die Schlüssel um und bricht den Hash). Entfernen Sie das sha256=-Präfix vom Signatur-Header. Berechnen Sie HMAC-SHA256(rawBody, secret) und vergleichen Sie zeitsicher mit dem empfangenen Hex.
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", 200curl (debugging)
# Recompute the signature locally and compare with the header. echo -n "$RAW_BODY" | openssl dgst -sha256 -hmac "$WEBHOOK_SECRET"
timingSafeEqual / hmac.compare_digest — verwenden Sie immer einen konstanten Zeitvergleich, damit Angreifer das Geheimnis nicht Byte für Byte abtasten können.
§ 05Ereigniskatalog
Heute feuert die Plattform vier Ereignistypen. Wir fügen mehr hinzu, wenn Features ausgeliefert werden — abonnieren Sie *, wenn Sie Vorwärtskompatibilität wollen.
| Ereignis | Feuert wenn | Datenform |
|---|---|---|
| message.created | Eine neue Nachricht landet in einem Gespräch, unabhängig vom Absender (Kunde eingehend, Agent ausgehend, REST-API-Versand). | { conversationId, message } |
| conversation.updated | Der Status eines Gesprächs (OPEN · SNOOZED · CLOSED) oder dessen assignedAgentId ändert sich. | { conversationId, status?, assignedAgentId? } |
| audit.event | Wann immer eine Audit-Log-Zeile geschrieben wird — Agent-Login, Rollenwechsel, Integration erstellt, Schlüssel widerrufen, etc. (Enterprise-Plan.) | { action, entity, entityId, actorId, metadata } |
| webhook.test | Sie klicken auf "Test" unter Einstellungen → Webhooks. Signiert und geformt genau wie ein echtes Ereignis. | { tenantId, test: true } |
Abonnieren Sie *, um jedes aktuelle und zukünftige Ereignis zu empfangen. Abonnieren Sie bestimmte Namen, wenn Sie einschränken wollen, was Ihr Handler wissen muss.
§ 06Integration testen
Die Schaltfläche "Test" in Einstellungen → Webhooks feuert ein webhook.test-Ereignis an Ihren Endpunkt und meldet den Upstream-HTTP-Status sowie die verstrichene Zeit. Verwenden Sie sie, um Ihren Handler zu validieren, bevor Sie echten Traffic dorthin leiten.
Die Test-Payload nutzt genau dasselbe Body-Envelope, dieselben Header-Namen und dasselbe HMAC-Schema wie Produktionsereignisse — wenn Ihre Verifizierung für webhook.test besteht, besteht sie auch für message.created und alles andere.
§ 07Wiederholungen & Zeitüberschreitungen
Wir geben Ihrem Server 10 Sekunden zum Antworten. Jeder Nicht-2xx-Status oder Netzwerkfehler ist ein Fehlschlag. Fehlgeschlagene Zustellungen werden bis zu 5-mal mit exponentiellem Backoff ab 2 Sekunden wiederholt, sodass ein unzuverlässiger Endpunkt mehrere Chancen bekommt, bevor wir das Ereignis aufgeben.
Wir garantieren KEINE Exactly-Once-Zustellung — bei Netzwerk-Flapping kann dasselbe Ereignis zweimal eintreffen. Machen Sie Ihren Handler idempotent: dedupliziere anhand der inneren data.message.id (oder welche ID auch immer für dieses Ereignis sinnvoll ist).
§ 08Sicherheits-Checkliste
- Verwenden Sie immer https:// — reine http://-Endpunkte werden bei der Erstellung abgelehnt.
- Wir blockieren private, Loopback- und Cloud-Metadaten-IPs sowohl bei der Erstellung als auch bei der Zustellung, sodass ein falsch konfigurierter DNS-Eintrag nicht zum Pivoten in Ihr Netzwerk verwendet werden kann.
- Vergleichen Sie Signaturen mit einem zeitsicheren Gleichheit (Node crypto.timingSafeEqual, Python hmac.compare_digest, Go hmac.Equal).
- Rotieren Sie, indem Sie den Endpunkt löschen und einen neuen mit derselben URL erstellen. Aktualisieren Sie Ihren Secret-Store atomar.