ThunderPhone 2.0 er lanceret.Selvbetjening fra 2 cent pr. minut.Læs mere om lanceringen

Webhooks

Oversigt over webhooks

Sådan leverer ThunderPhone hændelser i realtid, hvordan du verificerer signaturer, og hvordan de ældre og endpoint-baserede leveringsmodeller sammenlignes.

ThunderPhone sender HTTP-POST-anmodninger til din server, når der sker noget under et opkald — et indgående opkald starter, et opkald slutter, en evalueringskørsel fuldføres, en alarm udløses osv. Der er to leveringsmodeller:

Alle angivne hændelsestyper i hændelseskataloget leveres via webhook-slutpunkter. De seks opkaldslivscyklushændelser (telephony.incoming, telephony.complete, telephony.tool, web.incoming, web.complete, web.tool) sendes også til den ældre webhook med enkelt URL — hvis du både har en ældre URL og et matchende slutpunkt, modtager du hændelsen på begge stier. Blokerende adfærd (telephony.incoming / web.incoming-konfigurationsudvekslingen og værktøjsafsendelse i webhooktilstand) findes udelukkende på den ældre sti; hver levering til et slutpunkt er en fire-and-forget-notifikation.

Payloadformat

Leveringer til slutpunkter er et JSON-objekt med data, event_id og type:

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

event_id er unik for hver udsendt hændelse. Den er identisk på tværs af genforsøg og på tværs af hvert slutpunkt, der modtager hændelsen — dedupliker efter den.

Den ældre webhook med enkelt URL sender samme type og data, men uden event_id:

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

På netværket serialiseres hver body kanonisk — nøgler sorteres alfabetisk, uden mellemrum, UTF-8. De formaterede eksempler i denne dokumentation er kun for læsbarhed.

Se hændelseskataloget for den fulde liste over hændelsestyper og payloadfelter.

Signaturverificering

Hver anmodning indeholder to signaturer, begge HMAC-SHA256 med endpointets secret som nøgle (eller din organisations webhook-secret for ældre leveringer):

  • X-ThunderPhone-Signature-V2: t=<unix seconds>,v1=<hex> signerer tidsstemplet, metoden, stien og forespørgslen samt den rå body. Verificer denne, og afvis anmodninger, hvis t er mere end 5 minutter fra dit ur, så en opsnappet anmodning ikke kan afspilles igen senere. Gentagelser signeres igen, når de sendes.
  • X-ThunderPhone-Signature signerer kun den rå body. Den sendes stadig uændret, så eksisterende verifikatorer fortsat fungerer.

Trin

  1. Læs headeren, metoden, den rå sti og forespørgsel samt den rå body før enhver parsing.
  2. Beregn den hexadecimale HMAC-SHA256 for <t>\n<METHOD>\n<path and query>\n<body> med din hemmelighed.
  3. Afvis anmodningen, hvis t afviger med mere end 300 sekunder, eller hvis resultatet ikke matcher v1 i en sammenligning med konstant tid.

Bodies er den kanoniske JSON-serialisering (sorterede nøgler, kompakte separatorer), og vi signerer nøjagtigt de bytes, vi sender. Guiden til verificering indeholder den nøjagtige signerede streng, et gennemarbejdet eksempel, kode uden SDK'et og den ældre 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);
  },
);

Leveringssemantik

Disse semantikker gælder for leverancer til endpoint. Den ældre webhook med én URL er ét synkront forsøg uden genforsøg, bortset fra konfigurationsudvekslingen for telefonopkaldet telephony.incoming, som genforsøges én gang.

Genforsøg

Hver hændelse forsøges leveret én gang med det samme. Ethvert 2xx-svar bekræfter leverancen. Ved ethvert andet udfald (ikke-2xx, forbindelsesfejl, timeout) genforsøger vi efter 1 m, 5 m, 30 m, 2 h, 6 h, 12 h og 24 h efter det første forsøg — 8 forsøg fordelt over 24 timer. Hvis alle forsøg fejler, stopper leverancen, og endpointet markeres med status="failing" i webhook-endpoints; vi sender en e-mail til din organisations ejere og administratorer og viser det i dashboardet. Returner 2xx, så snart payloaden er accepteret varigt; behandl den asynkront. Testafsendelser fra endpoint-test-API'et får ét genforsøg cirka et minut efter det første forsøg og ændrer aldrig endpointets status.

Rækkefølge

Leveringsrækkefølgen er efter bedste evne. I praksis leverer vi i den rækkefølge, hændelser udsendes, men genforsøg kan ændre rækkefølgen ved fejl. Dedupliker og afstem altid efter call_id / objekt-id.

Dubletter

Levering er mindst én gang: et genforsøg efter et svar, vi aldrig modtog, kan duplikere en hændelse. Hvert genforsøg har samme event_id, så gem behandlede id'er, og spring gentagelser over. event_id deles også på tværs af endepunkter — to endepunkter, der abonnerer på den samme hændelse, modtager den samme event_id.

Timeouts

Leverancer til endpoints har en timeout på 30 s pr. forsøg. På den ældre sti er blokerende anmodninger, der styrer aktiv opkaldsadfærd — konfigurationsudvekslingen telephony.incoming / web.incoming — begrænset til 10 s for et telefonopkalds første forsøg og 13 s for hele udvekslingen inklusive det ene genforsøg, og til 10 s for en widgetsession. Et langsomt svar forsinker besvarelsen af opkaldet, så sigt efter at svare inden for et par sekunder. Værktøjsafsendelse i webhooktilstand tillader 20 s som standard, og værktøjsdeklarationer kan angive en timeout på øverste niveau.

Kilde-IP'er

Udgående webhooks kommer fra ThunderPhones cloud-IP-område. Hvis din firewall kræver en tilladelsesliste, skal du kontakte support, så deler vi de aktuelle områder.

Valg mellem ældre og endepunktbaserede webhooks

FunktionÆldre (/v1/webhook)Endepunkter (/v1/developer/webhook-endpoints)
Antal URL'er1 pr. organisationMange pr. organisation
HændelsesdækningKun telephony.* / web.*Alle 10 hændelsestyper
Hændelsesfilter—Pr. endepunkt
GenforsøgIngen, undtagen ét for konfigurationsudvekslingen for telefonopkald8 forsøg over 24 timer
Konvoluttype + datatype + data + event_id
Rotation af hemmelighedErstatter én hemmelighedHemmelighed pr. endepunkt
Deaktiver uden at slettePUT /v1/webhook med {"url": ""}status=disabled
Synlighed af status—active / disabled / failing
Blokerende konfigurationsudvekslingJa (telephony.incoming / web.incoming)Aldrig — kun notifikationer
Bedst tilDynamisk opkaldskonfigurationHændelsesforbrug i produktion

Nye integrationer bør forbruge hændelser via endepunktbaserede webhooks. Behold (eller tilføj) kun en ældre URL, hvis du konfigurerer opkald dynamisk ved besvarelse eller bruger værktøjsafvikling i webhooktilstand — disse anmodnings-/svarudvekslinger kører kun på den ældre sti.


Relateret