ThunderPhone 2.0 je tu.Začnite sami, už od 2 ¢/min.Prečítať oznámenie

Webhooks

Prehľad webhookov

Ako ThunderPhone doručuje udalosti v reálnom čase, ako overovať podpisy a ako sa porovnávajú starší model doručovania a model založený na koncových bodoch.

ThunderPhone odosiela na váš server požiadavky HTTP POST, keď počas hovoru nastanú udalosti — začne sa prichádzajúci hovor, hovor sa skončí, dokončí sa hodnotenie, spustí sa upozornenie a podobne. Existujú dva modely doručovania:

Všetkých desať typov udalostí v katalógu udalostí sa doručuje prostredníctvom koncových bodov webhookov. Šesť udalostí životného cyklu hovoru (telephony.incoming, telephony.complete, telephony.tool, web.incoming, web.complete, web.tool) sa zároveň odosiela do staršieho webhooku s jednou adresou URL — ak máte staršiu adresu URL aj zodpovedajúci koncový bod, udalosť dostanete na oboch cestách. Blokujúce správanie (výmena konfigurácie telephony.incoming / web.incoming a odoslanie nástroja v režime webhooku) je dostupné výlučne na staršej ceste; každé doručenie na koncový bod je oznámenie typu fire-and-forget.

Formát dátovej časti

Doručenia na koncový bod sú objekty JSON s položkami data, event_id a type:

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

event_id je jedinečný pre každú odoslanú udalosť. Je identický pri opakovaniach aj na všetkých koncových bodoch, ktoré udalosť prijmú — používajte ho na deduplikáciu.

Starší webhook s jednou adresou URL odosiela rovnaké type a data, ale bez event_id:

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

Pri prenose je každé telo serializované kanonicky — kľúče sú zoradené abecedne, bez medzier, v kódovaní UTF-8. Príklady s formátovaním v tejto dokumentácii slúžia len na lepšiu čitateľnosť.

Úplný zoznam typov udalostí a polí dátovej časti nájdete v katalógu udalostí.

Overenie podpisu

Každá požiadavka obsahuje v hlavičke X-ThunderPhone-Signature podpis HMAC-SHA256 vytvorený nad nespracovaným telom požiadavky. Podpisovací kľúč je secret koncového bodu (alebo secret webhooku na úrovni vašej organizácie pre staršie doručenia).

Kroky

  1. Prečítajte nespracované telo požiadavky pred akýmkoľvek spracovaním.
  2. Vypočítajte hmac_sha256(secret, body).hexdigest().
  3. Porovnajte výsledok v konštantnom čase s hlavičkou X-ThunderPhone-Signature.

Podpisujeme presne tie bajty, ktoré odosielame, a tieto bajty sú kanonickou serializáciou JSON (zoradené kľúče, kompaktné oddeľovače). Overovanie voči nespracovanému telu preto vždy funguje — a ak vám váš framework poskytne iba spracovaný JSON, jeho opätovná serializácia so zoradenými kľúčmi a kompaktnými oddeľovačmi vytvorí identické bajty. Oba postupy sú uvedené v návode na overenie.

Python
import hmac
import hashlib
 
def verify_signature(body: bytes, signature: str, secret: str) -> bool:
    expected = hmac.new(
        secret.encode("utf-8"),
        body,
        hashlib.sha256,
    ).hexdigest()
    return hmac.compare_digest(expected, signature or "")
 
# Example Flask handler
from flask import Flask, request, abort
app = Flask(__name__)
 
@app.post("/thunderphone-webhook")
def handle():
    body = request.get_data()
    sig = request.headers.get("X-ThunderPhone-Signature", "")
    if not verify_signature(body, sig, WEBHOOK_SECRET):
        abort(401)
    event = request.get_json()
    # dispatch on event["type"] …
    return "", 204
Node.js (Express)
import crypto from "node:crypto";
import express from "express";
 
function verifySignature(body, signature, secret) {
  const expected = crypto
    .createHmac("sha256", secret)
    .update(body)
    .digest("hex");
  if (!signature || expected.length !== signature.length) return false;
  return crypto.timingSafeEqual(
    Buffer.from(expected),
    Buffer.from(signature),
  );
}
 
const app = express();
app.post(
  "/thunderphone-webhook",
  express.raw({ type: "application/json" }),
  (req, res) => {
    const sig = req.header("X-ThunderPhone-Signature") || "";
    if (!verifySignature(req.body, sig, process.env.WEBHOOK_SECRET)) {
      return res.sendStatus(401);
    }
    const event = JSON.parse(req.body.toString("utf8"));
    // dispatch on event.type …
    res.sendStatus(204);
  },
);

Sémantika doručovania

Táto sémantika sa vzťahuje na doručovanie do koncových bodov. Starší webhook s jednou URL je jeden synchrónny pokus bez opakovaní.

Opakovania

Každá udalosť sa okamžite pokúsi doručiť raz. Každá odpoveď 2xx potvrdzuje doručenie. Pri akomkoľvek inom výsledku (nie-2xx, chyba pripojenia, časový limit) pokus zopakujeme 1 min, 5 min, 30 min, 2 h, 6 h, 12 h a 24 h po prvom pokuse — 8 pokusov počas 24 hodín. Ak zlyhajú všetky pokusy, doručovanie sa zastaví a koncový bod sa v koncových bodoch webhookov označí stavom status="failing". Vráťte 2xx hneď po trvalom prijatí payloadu; spracujte ho asynchrónne.

Poradie

Poradie doručovania je v rámci možností zachované. V praxi doručujeme v poradí, v akom sú udalosti emitované, ale opakovania môžu pri zlyhaní poradie zmeniť. Vždy odstráňte duplicity a zosúlaďte údaje podľa call_id / ID objektu.

Duplikáty

Doručovanie je aspoň raz: opakovanie po odpovedi, ktorú sme nikdy nezaznamenali, môže vytvoriť duplicitnú udalosť. Každé opakovanie obsahuje rovnaké event_id, preto ukladajte spracované ID a preskakujte opakovania. event_id je zdieľané aj medzi koncovými bodmi — dva koncové body prihlásené na odber rovnakej udalosti dostanú rovnaké event_id.

Časové limity

Doručovanie do koncových bodov má časový limit 30 s na pokus. V staršej ceste blokujúce požiadavky, ktoré riadia správanie aktívneho hovoru — výmena konfigurácie telephony.incoming / web.incoming — vypršia po 10 s, ale pomalá odpoveď oneskorí prijatie hovoru, preto sa snažte odpovedať do niekoľkých sekúnd. Odosielanie nástrojov v režime webhooku tool dispatch predvolene umožňuje 20 s a deklarácie nástrojov môžu nastaviť timeout na najvyššej úrovni.

Zdrojové IP adresy

Odchádzajúce webhooky pochádzajú z cloudového rozsahu IP adries ThunderPhone. Ak váš firewall vyžaduje zoznam povolených adries, kontaktujte podporu a poskytneme vám aktuálne rozsahy.

Výber medzi staršími webhookmi a webhookmi založenými na koncových bodoch

FunkciaStaršie (/v1/webhook)Koncové body (/v1/developer/webhook-endpoints)
Počet URL1 na organizáciuViac na organizáciu
Pokrytie udalostíLen telephony.* / web.*Všetkých 10 typov udalostí
Filter udalostíPre každý koncový bod
OpakovaniaŽiadne8 pokusov počas 24 h
Obálkatype + datatype + data + event_id
Rotácia tajného kľúčaNahrádza jediný tajný kľúčTajný kľúč pre každý koncový bod
Zakázanie bez odstráneniaPUT /v1/webhook s {"url": ""}status=disabled
Viditeľnosť stavuactive / disabled / failing
Blokujúca výmena konfigurácieÁno (telephony.incoming / web.incoming)Nikdy — iba oznámenia
Najvhodnejšie preDynamickú konfiguráciu hovorovSpracovanie udalostí v produkcii

Nové integrácie by mali udalosti spracúvať prostredníctvom webhookov založených na koncových bodoch. Staršiu URL ponechajte (alebo pridajte) len v prípade, že konfigurujete hovory dynamicky pri ich prijatí alebo používate odosielanie nástrojov v režime webhooku — tieto výmeny požiadaviek a odpovedí fungujú iba v staršej ceste.


Súvisiace