ThunderPhone 2.0 ist live.Direkt im Self-Service – ab 2 ¢/Min..Ankündigung lesen

Webhooks

Webhooks – Übersicht

Wie ThunderPhone Ereignisse in Echtzeit übermittelt, wie Sie Signaturen verifizieren und wie sich die Legacy- und die endpunktbasierten Zustellmodelle vergleichen.

ThunderPhone sendet HTTP-POST-Anfragen an Ihren Server, wenn während eines Anrufs Ereignisse eintreten — ein eingehender Anruf beginnt, ein Anruf endet, ein Bewertungsdurchlauf abgeschlossen wird, eine Warnung ausgelöst wird usw. Es gibt zwei Zustellungsmodelle:

Alle aufgeführten Ereignistypen im Ereigniskatalog werden über Webhook-Endpunkte zugestellt. Die sechs Ereignisse des Anruflebenszyklus (telephony.incoming, telephony.complete, telephony.tool, web.incoming, web.complete, web.tool) werden auch an den Legacy-Webhook mit einzelner URL gesendet — wenn Sie sowohl eine Legacy-URL als auch einen passenden Endpunkt haben, erhalten Sie das Ereignis über beide Pfade. Das blockierende Verhalten (der Konfigurationsaustausch für telephony.incoming / web.incoming und die Tool-Weiterleitung im Webhook-Modus) ist ausschließlich auf dem Legacy-Pfad verfügbar; jede Endpunktzustellung ist eine Fire-and-Forget-Benachrichtigung.

Payload-Format

Endpunktzustellungen sind ein JSON-Objekt mit data, event_id und type:

{
  "data": {
    "call_id": 987654321,
    "from_number": "+14155550199",
    "to_number": "+15551234567"
  },
  "event_id": "3f6b2ad0-1c9e-4a57-9f2b-8f6f0f9d2f11",
  "type": "telephony.incoming"
}

event_id ist für jedes ausgegebene Ereignis eindeutig. Sie ist bei Wiederholungen und bei jedem Endpunkt, der das Ereignis empfängt, identisch — verwenden Sie sie zur Deduplizierung.

Der Legacy-Webhook mit einzelner URL sendet denselben type und dieselben data, jedoch ohne event_id:

{
  "type": "telephony.incoming",
  "data": { "call_id": 987654321, "from_number": "+14155550199", "to_number": "+15551234567" }
}

Bei der Übertragung wird jeder Body kanonisch serialisiert — Schlüssel werden alphabetisch sortiert, ohne Leerzeichen, in UTF-8. Die formatierten Beispiele in diesen Docs dienen nur der Lesbarkeit.

Im Ereigniskatalog finden Sie die vollständige Liste der Ereignistypen und Payload-Felder.

Signaturverifizierung

Jede Anfrage enthält zwei Signaturen, die beide mit HMAC-SHA256 und dem secret des Endpunkts signiert sind (oder dem Webhook-secret Ihrer Organisation für Legacy-Zustellungen):

  • X-ThunderPhone-Signature-V2: t=<unix seconds>,v1=<hex> signiert den Zeitstempel, die Methode, den Pfad und die Abfrage sowie den Rohtextkörper. Überprüfen Sie diese Signatur und lehnen Sie Anfragen ab, deren t mehr als 5 Minuten von Ihrer Uhr abweicht, damit eine abgefangene Anfrage später nicht erneut abgespielt werden kann. Wiederholungsversuche werden beim Senden erneut signiert.
  • X-ThunderPhone-Signature signiert nur den Rohtextkörper. Sie wird weiterhin unverändert gesendet, damit vorhandene Verifizierer weiterhin funktionieren.

Schritte

  1. Lesen Sie den Header, die Methode, den Rohpfad und die Abfrage sowie den rohen Body vor jeder Verarbeitung.
  2. Berechnen Sie den hexadezimalen HMAC-SHA256 von <t>\n<METHOD>\n<path and query>\n<body> mit Ihrem Secret.
  3. Lehnen Sie die Anfrage ab, wenn t um mehr als 300 Sekunden abweicht oder das Ergebnis bei einem Vergleich mit konstanter Laufzeit nicht mit v1 übereinstimmt.

Bodys verwenden die kanonische JSON-Serialisierung (sortierte Schlüssel, kompakte Trennzeichen), und wir signieren genau die Bytes, die wir übertragen. Der Leitfaden zur Verifizierung enthält den exakt signierten String, ein durchgerechnetes Beispiel, Code ohne SDK und den veralteten Header.

Python (Flask)
from flask import Flask, abort, request
from thunderphone import verify_signature
 
app = Flask(__name__)
 
@app.post("/thunderphone-webhook")
def handle():
    query = request.query_string.decode()
    if not verify_signature(
        request.headers.get("X-ThunderPhone-Signature-V2"),
        secret=WEBHOOK_SECRET,
        method=request.method,
        path=request.path + (f"?{query}" if query else ""),
        body=request.get_data(),  # raw bytes
    ):
        abort(401)
    event = request.get_json()
    # dispatch on event["type"] …
    return "", 204
Node.js (Express)
import express from "express";
import { verifySignature } from "@thunderphone/sdk";
 
const app = express();
app.post(
  "/thunderphone-webhook",
  express.raw({ type: "application/json" }),
  (req, res) => {
    const ok = verifySignature({
      header: req.header("X-ThunderPhone-Signature-V2"),
      secret: process.env.WEBHOOK_SECRET,
      method: req.method,
      path: req.originalUrl,
      body: req.body,
    });
    if (!ok) return res.sendStatus(401);
    const event = JSON.parse(req.body.toString("utf8"));
    // dispatch on event.type …
    res.sendStatus(204);
  },
);

Zustellungssemantik

Diese Semantik gilt für Zustellungen an Endpunkte. Der ältere Webhook mit einer einzelnen URL führt einen einzigen synchronen Versuch ohne Wiederholungen aus, mit Ausnahme des Konfigurationsaustauschs für Telefonanrufe von telephony.incoming, der einmal wiederholt wird.

Wiederholungen

Jedes Ereignis wird sofort einmal zugestellt. Jede 2xx-Antwort bestätigt die Zustellung. Bei jedem anderen Ergebnis (kein 2xx, Verbindungsfehler, Zeitüberschreitung) wiederholen wir den Versuch 1 Min., 5 Min., 30 Min., 2 Std., 6 Std., 12 Std. und 24 Std. nach dem ersten Versuch — 8 Versuche über 24 Stunden. Wenn jeder Versuch fehlschlägt, wird die Zustellung beendet und der Endpunkt in Webhook-Endpunkten mit status="failing" markiert; wir senden den Eigentümern und Administratoren Ihrer Organisation eine E-Mail und zeigen dies im Dashboard an. Geben Sie 2xx zurück, sobald die Nutzlast dauerhaft angenommen wurde; verarbeiten Sie sie asynchron. Testsendungen über die Endpunkt-Test-API erhalten etwa eine Minute nach dem ersten Versuch eine Wiederholung und ändern niemals den Status des Endpunkts.

Reihenfolge

Die Zustellreihenfolge erfolgt nach bestem Bemühen. In der Praxis stellen wir Ereignisse in der Reihenfolge zu, in der sie ausgegeben werden, aber Wiederholungen können die Reihenfolge bei Fehlern ändern. Führen Sie immer Deduplizierung und Abgleich anhand von call_id / Objekt-ID durch.

Duplikate

Die Zustellung erfolgt mindestens einmal: Eine Wiederholung nach einer Antwort, die wir nie gesehen haben, kann ein Ereignis duplizieren. Jede Wiederholung enthält dieselbe event_id; speichern Sie daher verarbeitete IDs und überspringen Sie Wiederholungen. event_id wird auch zwischen Endpoints geteilt — zwei Endpoints, die dasselbe Ereignis abonniert haben, erhalten dieselbe event_id.

Zeitüberschreitungen

Zustellungen an Endpunkte haben pro Versuch eine Zeitüberschreitung von 30 s. Im älteren Pfad sind blockierende Anfragen, die das Verhalten laufender Anrufe steuern — der Konfigurationsaustausch telephony.incoming / web.incoming — für den ersten Versuch eines Telefonanrufs auf 10 s und für den gesamten Austausch einschließlich seiner einen Wiederholung auf 13 s begrenzt sowie auf 10 s für eine Widget-Sitzung. Eine langsame Antwort verzögert die Gesprächsannahme; antworten Sie daher innerhalb weniger Sekunden. Der Tool-Dispatch im Webhook-Modus erlaubt standardmäßig 20 s, und Tool-Deklarationen können ein timeout auf oberster Ebene festlegen.

Quell-IP-Adressen

Ausgehende Webhooks stammen aus dem Cloud-IP-Bereich von ThunderPhone. Wenn Ihre Firewall eine Allowlist erfordert, kontaktieren Sie den Support. Wir teilen Ihnen dann die aktuellen Bereiche mit.

Auswahl zwischen älteren und endpointbasierten Webhooks

FunktionLegacy (/v1/webhook)Endpunkte (/v1/developer/webhook-endpoints)
Anzahl der URLs1 pro OrganisationMehrere pro Organisation
EreignisabdeckungNur telephony.* / web.*Alle 10 Ereignistypen
Ereignisfilter—Pro Endpunkt
WiederholungsversucheKeine, außer einem für den Austausch zur Anrufkonfiguration8 Versuche innerhalb von 24 h
Ereignishülletype + datatype + data + event_id
Secret-RotationErsetzt einzelnes SecretSecret pro Endpunkt
Deaktivieren ohne LöschenPUT /v1/webhook mit {"url": ""}status=disabled
Statussichtbarkeit—active / disabled / failing
Blockierender KonfigurationsaustauschJa (telephony.incoming / web.incoming)Nie — nur Benachrichtigungen
Am besten geeignet fürDynamische AnrufkonfigurationEreignisverarbeitung in Produktion

Neue Integrationen sollten Ereignisse über endpointbasierte Webhooks verarbeiten. Behalten Sie eine ältere URL nur bei (oder fügen Sie eine hinzu), wenn Sie Anrufe beim Zeitpunkt der Annahme dynamisch konfigurieren oder die webhookbasierte Tool-Ausführung verwenden — diese Anfrage-/Antwortaustausche laufen nur über den älteren Pfad.


Verwandte Inhalte