ThunderPhone 2.0 je stigao.Postavite sve sami, već od 2 ¢/min.Pročitajte objavu

Webhooks

Pregled webhookova

Kako ThunderPhone isporučuje događaje u stvarnom vremenu, kako provjeriti potpise i kako se uspoređuju naslijeđeni modeli isporuke i modeli isporuke temeljeni na krajnjim točkama.

ThunderPhone šalje HTTP POST zahtjeve na Vaš poslužitelj kada se tijekom poziva dogode određene radnje — započne dolazni poziv, poziv završi, dovrši se pokretanje ocjenjivanja, aktivira se upozorenje i slično. Postoje dva modela isporuke:

Sve navedene vrste događaja u katalogu događaja isporučuju 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 zastarjeli webhook s jednim URL-om — ako imate i zastarjeli URL i odgovarajuću krajnju točku, događaj primate na obje putanje. Blokirajuće ponašanje (razmjena konfiguracije za telephony.incoming / web.incoming i otprema alata u načinu rada webhooka) dostupno je isključivo na zastarjeloj putanji; svaka isporuka na krajnju točku obavijest je bez čekanja odgovora.

Format sadržaja

Isporuke na krajnju točku 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. Jednak je pri ponovnim pokušajima i na svakoj krajnjoj točki koja primi događaj — upotrijebite ga za uklanjanje duplikata.

Zastarjeli webhook s jednim URL-om šalje isti type i data, ali bez polja event_id:

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

Pri prijenosu se svako tijelo kanonski serijalizira — ključevi su poredani abecedno, bez razmaka, u UTF-8 formatu. Primjeri s uvlačenjem u ovoj dokumentaciji služe samo radi čitljivosti.

Pogledajte Katalog događaja za potpuni popis vrsta događaja i polja sadržaja.

Provjera potpisa

Svaki zahtjev sadrži dva potpisa, oba HMAC-SHA256 s ključem secret krajnje točke (ili vašim secret ključem webhooka na razini organizacije za naslijeđene isporuke):

  • X-ThunderPhone-Signature-V2: t=<unix seconds>,v1=<hex> potpisuje vremensku oznaku, metodu, putanju i upit te sirovo tijelo. Provjerite ovaj potpis i odbijte zahtjeve čiji je t udaljen više od 5 minuta od vašeg sata kako se presretnuti zahtjev kasnije ne bi mogao ponovno poslati. Ponovni pokušaji ponovno se potpisuju kada se pošalju.
  • X-ThunderPhone-Signature potpisuje samo sirovo tijelo. I dalje se šalje nepromijenjen kako bi postojeći alati za provjeru nastavili raditi.

Koraci

  1. Pročitajte zaglavlje, metodu, neobrađenu putanju i upit te neobrađeno tijelo prije bilo kakve obrade.
  2. Izračunajte heksadecimalni HMAC-SHA256 za <t>\n<METHOD>\n<path and query>\n<body> pomoću svoje tajne.
  3. Odbijte zahtjev ako t odstupa više od 300 sekundi ili ako se rezultat ne podudara s v1 pri usporedbi u konstantnom vremenu.

Tijela su kanonska JSON serializacija (sortirani ključevi, sažeti razdjelnici), a potpisujemo točno bajtove koje prenosimo. Vodič za provjeru sadrži točan potpisani niz, obrađeni primjer, kôd bez SDK-a i naslijeđeno zaglavlje.

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

Semantika isporuke

Ova se semantika primjenjuje na isporuke krajnjim točkama. Naslijeđeni webhook s jednim URL-om jedan je sinkroni pokušaj bez ponovnih pokušaja, osim razmjene konfiguracije za telefonski poziv telephony.incoming, koja se ponavlja jednom.

Ponovni pokušaji

Svaki se događaj odmah pokušava isporučiti jednom. Svaki odgovor 2xx potvrđuje isporuku. U svakom drugom slučaju (odgovor koji nije 2xx, pogreška veze, istek vremena) ponavljamo pokušaj 1 m, 5 m, 30 m, 2 h, 6 h, 12 h i 24 h nakon prvog pokušaja — ukupno 8 pokušaja tijekom 24 sata. Ako svaki pokušaj ne uspije, isporuka se zaustavlja, a krajnja točka označava se s status="failing" u webhook krajnjim točkama; e-poštom obavještavamo vlasnike i administratore vaše organizacije te to prikazujemo na nadzornoj ploči. Vratite 2xx čim se teret trajno prihvati; obradite ga asinkrono. Testna slanja iz API-ja za testiranje krajnje točke dobivaju jedan ponovni pokušaj otprilike minutu nakon prvog pokušaja i nikad ne mijenjaju status krajnje točke.

Redoslijed

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

Duplikati

Isporuka je najmanje jednom: ponovni pokušaj nakon odgovora koji nikada nismo vidjeli može duplicirati događaj. Svaki ponovni pokušaj nosi isti event_id, stoga pohranite obrađene ID-jeve i preskočite ponavljanja. event_id se također dijeli među 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 — ograničeni su na 10 s za prvi pokušaj telefonskog poziva i 13 s za cijelu razmjenu, uključujući jedan ponovni pokušaj, te na 10 s za sesiju widgeta. Spor odgovor odgađa preuzimanje poziva, stoga nastojte odgovoriti u roku od nekoliko sekundi. Slanje alata u načinu rada webhooka prema zadanim postavkama dopušta 20 s, a deklaracije alata mogu postaviti timeout na najvišoj razini.

Izvorne IP adrese

Izlazni 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đaja—Po krajnjoj točki
Ponovni pokušajiNema, osim jednoga za razmjenu konfiguracije telefonskog poziva8 pokušaja tijekom 24 h
Omotnicatype + datatype + data + event_id
Rotacija tajneZamjenjuje jednu tajnuTajna po krajnjoj točki
Onemogućavanje bez brisanjaPUT /v1/webhook s {"url": ""}status=disabled
Vidljivost statusa—active / disabled / failing
Blokirajuća razmjena konfiguracijeDa (telephony.incoming / web.incoming)Nikada — samo obavijesti
Najbolje zaDinamičku konfiguraciju pozivaPrimanje događaja u produkciji

Nove integracije trebaju primati događaje putem webhookova temeljenih na krajnjim točkama. Zadržite (ili dodajte) naslijeđeni URL samo ako konfigurirate pozive dinamički u trenutku javljanja ili upotrebljavate slanje alata u načinu rada webhooka — te se razmjene zahtjeva i odgovora izvršavaju samo na naslijeđenoj putanji.


Povezano