Webhooks
TapToChat kann bei jedem Ereignis eine HTTPS-Anfrage an einen Server senden: eine neue Unterhaltung, eine Nachricht, eine Zuweisung. Jede Anfrage ist signiert, damit ihre Herkunft überprüfbar ist.
Einen Webhook einrichten
Webhooks gehören zum Pro-Tarif. Inhaber und Admins verwalten sie in den Einstellungen.
- Einstellungen → Webhooks öffnen und „Webhook hinzufügen“ wählen.
- Einen Namen und die https-URL angeben, die die Ereignisse empfangen soll.
- Die zu sendenden Ereignisse auswählen.
- Das Signatur-Secret kopieren. Es wird nur einmal angezeigt und lässt sich später erneuern.
Ereignisse
Jeder Webhook erhält nur die Ereignisse, die er abonniert hat.
| Ereignis | Gesendet, wenn |
|---|---|
conversation.created | ein Besucher eine Unterhaltung beginnt, auf jedem Kanal. |
conversation.assigned | eine Unterhaltung einem Agenten zugewiesen wird. |
conversation.closed | eine Unterhaltung geschlossen wird. |
message.created | eine Nachricht gespeichert wird: von einem Besucher, einem Agenten oder als automatische Antwort. |
tag.added | einer Unterhaltung ein Tag hinzugefügt wird. |
note.created | ein Agent eine interne Notiz hinzufügt oder einen Befehl wie /summary ausführt, dessen Ergebnis als Notiz gespeichert wird (kind command_result). |
integration.connected | eine Integration verbunden wird. |
integration.disconnected | eine Integration getrennt wird. |
integration.error | die Synchronisierung einer Integration fehlschlägt. |
webhook.test | in den Einstellungen „Testereignis senden“ gewählt wird. Sonst nie. |
Inhalt
Jede Anfrage ist ein POST mit einem JSON-Body in stets derselben Hülle:
{
"id": "6f1c2b0e-8a7d-4c1e-9b3a-2d5e7f9a1c4b",
"event": "message.created",
"created_at": "2026-10-01T09:30:00.000Z",
"organization_id": "0c9a1f4e-3b2d-4e5f-8a6b-7c8d9e0f1a2b",
"data": {
"message": {
"id": "a1b2c3d4-…",
"conversation_id": "e5f6a7b8-…",
"sender_type": "visitor",
"sender_id": null,
"content": "Hello, is anyone there?",
"channel": "web",
"created_at": "2026-10-01T09:30:00.000Z"
},
"conversation": { "id": "e5f6a7b8-…", "status": "open", "visitor_name": "Ada", "…": "…" }
}
}id: die Ereignis-ID. Eine wiederholte Zustellung trägt dieselbe ID, damit sich Duplikate erkennen lassen.event: der Ereignisname, wie in der Tabelle oben.data: was passiert ist. Die Felder hängen vom Ereignis ab; ein Nachrichtenereignis enthält die Nachricht und ihre Unterhaltung.
Header
X-TapToChat-Signature: die Signatur: v1= gefolgt von einem hexadezimalen HMAC-SHA256.X-TapToChat-Timestamp: der Zeitpunkt der Signatur, in Unix-Sekunden.X-TapToChat-Event: der Ereignisname.X-TapToChat-Delivery-Id: diese Zustellung. Jede Wiederholung trägt dieselbe ID.
Die Signatur prüfen
Ein HMAC-SHA256 aus Zeitstempel, einem Punkt und dem unveränderten Anfrage-Body berechnen, mit dem Signatur-Secret als Schlüssel, und in konstanter Zeit mit dem Signatur-Header vergleichen. Anfragen, deren Zeitstempel mehr als 5 Minuten von der eigenen Uhr abweicht, ablehnen, damit eine abgefangene Anfrage nicht erneut abgespielt werden kann.
Das ganze Secret einschließlich des Präfixes whsec_ als Schlüssel verwenden. Den unveränderten Body vor dem Parsen prüfen: neu serialisiertes JSON stimmt nicht überein.
import crypto from 'node:crypto'
// The raw request body, exactly as received: verify before parsing JSON.
export function verifyTapToChat(rawBody, headers, secret) {
const timestamp = headers['x-taptochat-timestamp']
const signature = headers['x-taptochat-signature']
if (!timestamp || !signature) return false
// Refuse old requests, so a captured one cannot be replayed later.
if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false
const expected =
'v1=' + crypto.createHmac('sha256', secret).update(`${timestamp}.${rawBody}`).digest('hex')
const a = Buffer.from(signature)
const b = Buffer.from(expected)
return a.length === b.length && crypto.timingSafeEqual(a, b)
}Wiederholungen
Eine Zustellung gilt als bestätigt, wenn innerhalb von 10 Sekunden ein 2xx-Status zurückkommt. Andernfalls wird sie wiederholt, mit bis zu 6 Versuchen insgesamt.
Die Wartezeiten zwischen den Versuchen betragen 30s, 60s, 120s, 240s, 480s.
Eine 4xx-Antwort außer 408 oder 429 beendet die Wiederholungen sofort, ebenso eine Weiterleitung: Weiterleitungen werden nicht verfolgt, daher die endgültige URL angeben.
Gelegentlich kann eine Zustellung mehrfach ankommen. Mit der ID im Body lässt sich jedes Ereignis genau einmal verarbeiten.
Automatische Abschaltung
Nach 20 fehlgeschlagenen Zustellungen in Folge wird der Webhook abgeschaltet, und die Einstellungen zeigen den Grund. Nach der Reparatur des Empfängers lässt er sich wieder einschalten; der Zähler beginnt dann neu.
Gut zu wissen
- Die URL muss https verwenden und auf eine öffentliche Adresse zeigen.
- Nachrichten, die Agenten aus der mobilen TapToChat-App senden, lösen message.created noch nicht aus. Nachrichten aus dem Web-Dashboard und aus allen Kanälen schon.
Funktioniert etwas nicht wie beschrieben? Kontakt aufnehmen.