ThunderPhone 2.0 is live.Direct zelf aan de slag, vanaf 2¢/min.Lees de aankondiging

Webhooks

Overzicht van webhooks

Hoe ThunderPhone realtime gebeurtenissen levert, hoe je handtekeningen verifieert en hoe de verouderde en eindpuntgebaseerde leveringsmodellen zich tot elkaar verhouden.

ThunderPhone stuurt HTTP-POST-verzoeken naar je server wanneer er iets gebeurt tijdens een oproep — een inkomende oproep begint, een oproep eindigt, een beoordelingsrun wordt voltooid, een waarschuwing wordt geactiveerd, enzovoort. Er zijn twee leveringsmodellen:

Alle vermelde gebeurtenistypen in de gebeurteniscatalogus worden geleverd via webhook-eindpunten. De zes gebeurtenissen in de oproeplevenscyclus (telephony.incoming, telephony.complete, telephony.tool, web.incoming, web.complete, web.tool) worden ook naar de verouderde webhook met één URL gestuurd — als je zowel een verouderde URL als een overeenkomend eindpunt hebt, ontvang je de gebeurtenis via beide paden. Blokkerend gedrag (de configuratie-uitwisseling voor telephony.incoming / web.incoming en tool-dispatch in webhookmodus) bestaat uitsluitend op het verouderde pad; elke levering aan een eindpunt is een fire-and-forgetmelding.

Payloadindeling

Leveringen aan eindpunten zijn een JSON-object met data, event_id en type:

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

event_id is uniek voor elke verzonden gebeurtenis. Het is identiek bij nieuwe pogingen en bij elk eindpunt dat de gebeurtenis ontvangt — dedupliceer op basis hiervan.

De verouderde webhook met één URL stuurt hetzelfde type en dezelfde data, maar zonder event_id:

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

Over het netwerk wordt elke body canoniek geserialiseerd — sleutels alfabetisch gesorteerd, geen witruimte, UTF-8. De mooi opgemaakte voorbeelden in deze documentatie zijn uitsluitend bedoeld voor leesbaarheid.

Zie de gebeurteniscatalogus voor de volledige lijst met gebeurtenistypen en payloadvelden.

Handtekeningverificatie

Elke aanvraag bevat twee handtekeningen, beide HMAC-SHA256 met als sleutel de secret van het eindpunt (of je webhook-secret op organisatieniveau voor verouderde leveringen):

  • X-ThunderPhone-Signature-V2: t=<unix seconds>,v1=<hex> ondertekent de tijdstempel, de methode, het pad en de query, en de onbewerkte body. Verifieer deze en weiger aanvragen waarvan t meer dan 5 minuten afwijkt van je klok, zodat een onderschepte aanvraag later niet opnieuw kan worden afgespeeld. Nieuwe pogingen worden opnieuw ondertekend wanneer ze worden verzonden.
  • X-ThunderPhone-Signature ondertekent alleen de onbewerkte body. Deze wordt nog steeds ongewijzigd verzonden, zodat bestaande verificateurs blijven werken.

Stappen

  1. Lees de header, de methode, het onbewerkte pad en de query, en de onbewerkte body vóór enige parsing.
  2. Bereken de hexadecimale HMAC-SHA256 van <t>\n<METHOD>\n<path and query>\n<body> met je geheim.
  3. Weiger de aanvraag als t meer dan 300 seconden afwijkt, of als het resultaat niet overeenkomt met v1 bij een vergelijking in constante tijd.

Bodies zijn de canonieke JSON-serialisatie (gesorteerde sleutels, compacte scheidingstekens), en we ondertekenen exact de bytes die we verzenden. De verificatiehandleiding bevat de exacte ondertekende tekenreeks, een uitgewerkt voorbeeld, code zonder de SDK en de verouderde 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);
  },
);

Bezorgsemantiek

Deze semantiek geldt voor leveringen aan endpoints. De verouderde webhook met één URL voert één synchrone poging uit zonder herpogingen, behalve de configuratie-uitwisseling voor telefoongesprekken van telephony.incoming, waarvoor één herpoging wordt uitgevoerd.

Herpogingen

Elk event wordt onmiddellijk één keer geprobeerd. Elke 2xx-respons bevestigt de levering. Bij elke andere uitkomst (geen 2xx, verbindingsfout, time-out) proberen we het opnieuw na 1 m, 5 m, 30 m, 2 h, 6 h, 12 h en 24 h na de eerste poging — 8 pogingen verspreid over 24 uur. Als elke poging mislukt, stopt de levering en wordt het endpoint gemarkeerd met status="failing" in webhook-endpoints; we e-mailen de eigenaren en beheerders van je organisatie en tonen dit in het dashboard. Retourneer 2xx zodra de payload duurzaam is geaccepteerd; verwerk deze asynchroon. Testverzendingen vanuit de endpoint-test-API krijgen ongeveer een minuut na de eerste poging één herpoging en wijzigen de status van het endpoint nooit.

Volgorde

De bezorgvolgorde is naar beste vermogen. In de praktijk leveren we in de volgorde waarin gebeurtenissen worden verzonden, maar nieuwe pogingen kunnen bij fouten de volgorde wijzigen. Dedupliqueer en stem altijd af op basis van call_id / object-id.

Duplicaten

Bezorging is minstens één keer: een nieuwe poging na een reactie die we nooit hebben gezien, kan een gebeurtenis dupliceren. Elke nieuwe poging bevat dezelfde event_id, dus sla verwerkte id's op en sla herhalingen over. event_id wordt ook gedeeld tussen eindpunten — twee eindpunten die op dezelfde gebeurtenis zijn geabonneerd ontvangen dezelfde event_id.

Time-outs

Leveringen aan endpoints hebben een time-out van 30 s per poging. Op het verouderde pad zijn blokkerende aanvragen die het gedrag van live oproepen aansturen — de configuratie-uitwisseling van telephony.incoming / web.incoming — beperkt tot 10 s voor de eerste poging van een telefoongesprek en 13 s voor de volledige uitwisseling, inclusief de ene herpoging, en tot 10 s voor een widgetsessie. Een trage respons vertraagt het opnemen van een oproep, dus probeer binnen enkele seconden te antwoorden. Toondispatch in webhookmodus tooldispatch staat standaard 20 s toe, en tooldeclaraties kunnen een timeout op hoofdniveau instellen.

Bron-IP's

Uitgaande webhooks zijn afkomstig uit het cloud-IP-bereik van ThunderPhone. Als je firewall een toelatingslijst vereist, neem dan contact op met support; we delen de actuele bereiken.

Kiezen tussen verouderde en op eindpunten gebaseerde webhooks

FunctieLegacy (/v1/webhook)Eindpunten (/v1/developer/webhook-endpoints)
Aantal URL's1 per organisatieMeerdere per organisatie
GebeurtenisdekkingAlleen telephony.* / web.*Alle 10 gebeurtenistypen
Gebeurtenisfilter—Per eindpunt
Nieuwe pogingenGeen, behalve één voor de configuratie-uitwisseling voor telefoongesprekken8 pogingen binnen 24 uur
Enveloptype + datatype + data + event_id
SecretrotatieVervangt één secretSecret per eindpunt
Uitschakelen zonder verwijderenPUT /v1/webhook met {"url": ""}status=disabled
Zichtbaarheid van status—active / disabled / failing
Blokkerende configuratie-uitwisselingJa (telephony.incoming / web.incoming)Nooit — alleen meldingen
Meest geschikt voorDynamische oproepconfiguratieGebeurtenissen verwerken in productie

Nieuwe integraties moeten gebeurtenissen verwerken via op eindpunten gebaseerde webhooks. Behoud (of voeg) alleen een verouderde URL toe als je oproepen dynamisch configureert bij het aannemen of toolverzending in webhookmodus gebruikt — die verzoek-/reactie-uitwisselingen worden alleen uitgevoerd via het verouderde pad.


Gerelateerd