Pregled web-dojavnika

ThunderPhone šalje HTTP POST zahtjeve vašem poslužitelju kada se tijekom poziva nešto dogodi — započne dolazni poziv, poziv završi, završi pokretanje ocjenjivanja, aktivira se upozorenje i tako dalje. Postoje dva modela isporuke:

Svih deset vrsta događaja u katalogu događaja isporučuje se putem krajnjih točaka webhooka. Šest događaja životnog ciklusa poziva (telephony.incoming, telephony.complete, telephony.tool, web.incoming, web.complete, web.tool) također se šalje na naslijeđeni webhook s jednim URL-om — ako imate i naslijeđeni URL i odgovarajuću krajnju točku, događaj primate na oba puta. Blokirajuće ponašanje (razmjena konfiguracije telephony.incoming / web.incoming i slanje alata u načinu rada webhooka) dostupno je isključivo na naslijeđenom putu; svaka isporuka krajnjoj točki jest obavijest bez čekanja odgovora.

Format korisnog tereta

Isporuke krajnjim točkama JSON su objekt s poljima data, event_id i type:

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

event_id je jedinstven za svaki emitirani događaj. Isti je pri ponovnim pokušajima i na svakoj krajnjoj točki koja primi događaj — uklanjajte duplikate prema njemu.

Naslijeđeni webhook s jednim URL-om šalje isti type i data, ali bez event_id:

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

Pri prijenosu je svako tijelo serijalizirano kanonski — ključevi su poredani abecedno, bez razmaka, u UTF-8 formatu. Primjeri s oblikovanim ispisom u ovoj dokumentaciji služe samo radi čitljivosti.

Pogledajte Katalog događaja za potpuni popis vrsta događaja i polja korisnog tereta.

Provjera potpisa

Svaki zahtjev sadrži HMAC-SHA256 potpis nad sirovim tijelom zahtjeva u zaglavlju X-ThunderPhone-Signature. Ključ za potpisivanje je secret krajnje točke (ili secret webhooka na razini vaše organizacije za naslijeđene isporuke).

Koraci

  1. Pročitajte sirovo tijelo zahtjeva prije bilo kakvog parsiranja.
  2. Izračunajte hmac_sha256(secret, body).hexdigest().
  3. Usporedite u konstantnom vremenu sa zaglavljem X-ThunderPhone-Signature.

Potpisujemo točno bajtove koje šaljemo, a ti su bajtovi kanonska JSON serijalizacija (sortirani ključevi, sažeti razdjelnici). Stoga provjera prema sirovom tijelu uvijek radi — a ako vam vaš okvir daje samo parsirani JSON, ponovna serijalizacija sa sortiranim ključevima i sažetim razdjelnicima daje identične bajtove. Oba su postupka obuhvaćena u vodiču za provjeru.

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
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);
  },
);

Semantika isporuke

Ova semantika primjenjuje se na isporuke krajnjim točkama. Naslijeđeni webhook s jednim URL-om jedan je sinkroni pokušaj bez ponovnih pokušaja.

Ponovni pokušaji

Svaki se događaj odmah pokušava isporučiti jednom. Svaki odgovor 2xx potvrđuje isporuku. Pri svakom drugom ishodu (koji nije 2xx, pogreška veze, istek vremena) ponovno pokušavamo nakon 1 minute, 5 minuta, 30 minuta, 2 sata, 6 sati, 12 sati i 24 sata od prvog pokušaja — 8 pokušaja tijekom 24 sata. Ako svaki pokušaj ne uspije, isporuka prestaje, a krajnja točka označava se s status="failing" u krajnjim točkama webhooka. Vratite 2xx čim se sadržaj trajno prihvati; obradite ga asinkrono.

Redoslijed

Redoslijed isporuke temelji se na najboljem mogućem nastojanju. U praksi isporučujemo prema redoslijedu generiranja događaja, ali ponovni pokušaji mogu promijeniti redoslijed nakon neuspjeha. Uvijek uklonite duplikate i uskladite podatke prema call_id / ID-u objekta.

Duplikati

Isporuka je najmanje jednom: ponovni pokušaj nakon odgovora koji nismo primili može duplicirati događaj. Svaki ponovni pokušaj nosi isti event_id, stoga pohranite obrađene ID-ove i preskočite ponavljanja. event_id je također zajednički svim krajnjim točkama — dvije krajnje točke pretplaćene na isti događaj primaju isti event_id.

Istek vremena

Isporuke krajnjim točkama imaju istek vremena od 30 s po pokušaju. Na naslijeđenoj putanji blokirajući zahtjevi koji upravljaju ponašanjem poziva uživo — razmjena konfiguracije telephony.incoming / web.incoming — istječu nakon 10 s, ali spor odgovor odgađa javljanje na poziv, stoga nastojte odgovoriti u roku od nekoliko sekundi. Slanje alata u načinu rada webhooka tool dispatch dopušta 20 s.

Izvorne IP adrese

Odlazni webhookovi dolaze iz ThunderPhoneova raspona IP adresa u oblaku. Ako vaš vatrozid zahtijeva popis dopuštenih adresa, obratite se podršci i podijelit ćemo trenutačne raspone.

Odabir između naslijeđenih webhookova i webhookova temeljenih na krajnjim točkama

ZnačajkaNaslijeđeni (/v1/webhook)Krajnje točke (/v1/developer/webhook-endpoints)
Broj URL-ova1 po organizacijiViše po organizaciji
Obuhvat događajaSamo telephony.* / web.*Svih 10 vrsta događaja
Filtar događajaPo krajnjoj točki
Ponovni pokušajiNema8 pokušaja tijekom 24 h
Omotnicatype + datatype + data + event_id
Rotacija tajneZamjenjuje jednu tajnuTajna po krajnjoj točki
Onemogućavanje bez brisanjastatus=disabled
Vidljivost statusaactive / disabled / failing
Blokirajuća razmjena konfiguracijeDa (telephony.incoming / web.incoming)Nikad — samo obavijesti
Najbolje zaDinamičku konfiguraciju pozivaPrimanje događaja u produkciji

Nove integracije trebale bi primati događaje putem webhookova temeljenih na krajnjim točkama. Zadržite (ili dodajte) naslijeđeni URL samo ako dinamički konfigurirate pozive pri javljanju ili koristite slanje alata u načinu rada webhooka — te razmjene zahtjeva i odgovora izvode se samo na naslijeđenoj putanji.


Povezano