Open in
Pregled web-dojavnika
Kako ThunderPhone isporučuje događaje u stvarnom vremenu, kako provjeriti potpise te usporedba naslijeđenog modela isporuke i modela isporuke temeljenog na krajnjim točkama.
ThunderPhone šalje HTTP POST zahtjeve vašem poslužitelju kada se tijekom poziva nešto dogodi — započne dolazni poziv, poziv završi, dovrši se pokretanje ocjenjivanja, aktivira se upozorenje i slično. Postoje dva modela isporuke:
Više URL-ova, tajne po krajnjoj točki, filtri događaja po krajnjoj točki
i automatski ponovni pokušaji.
Upravljajte putem GET/POST/PATCH/DELETE /v1/developer/webhook-endpoints.
Jedan URL po organizaciji. Prenosi događaje životnog ciklusa poziva, uključujući
blokirajuće razmjene konfiguracije. Njime se upravlja putem GET/PUT /v1/webhook.
Svih deset vrsta događaja iz kataloga 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 putem obje putanje. Blokirajuće
ponašanje (razmjena konfiguracije za telephony.incoming / web.incoming
i slanje alata u načinu rada webhooka)
postoji isključivo na naslijeđenoj putanji; svaka isporuka krajnjoj točki
obavijest je bez čekanja odgovora.
Format podataka
Isporuke krajnjoj točki 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 jedinstven je za svaki emitirani događaj. Isti je pri ponovnim pokušajima
i na svakoj krajnjoj točki koja primi događaj — upotrijebite ga za uklanjanje duplikata.
Naslijeđeni 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 serijalizira kanonski — ključevi su poredani abecedno, bez razmaka, u UTF-8 kodiranju. Primjeri s oblikovanim prikazom u ovoj dokumentaciji služe samo za čitljivost.
Pogledajte Katalog događaja za potpuni popis vrsta događaja i polja podataka.
Provjera potpisa
Svaki zahtjev nosi HMAC-SHA256 potpis nad izvornim tijelom
zahtjeva u zaglavlju X-ThunderPhone-Signature. Ključ za potpisivanje je
secret krajnje točke (ili secret vašeg webhooka na razini organizacije za
naslijeđene isporuke).
Koraci
- Pročitajte izvorno tijelo zahtjeva prije bilo kakvog parsiranja.
- Izračunajte
hmac_sha256(secret, body).hexdigest(). - Usporedite u konstantnom vremenu sa zaglavljem
X-ThunderPhone-Signature.
Potpisujemo točno bajtove koje šaljemo, a ti bajtovi predstavljaju kanonsku JSON serijalizaciju (sortirani ključevi, sažeti razdjelnici). Stoga provjera prema izvornom tijelu uvijek funkcionira — a ako vam vaš okvir prosljeđuje samo parsirani JSON, ponovna serijalizacija sa sortiranim ključevima i sažetim razdjelnicima stvara identične bajtove. Obje su metode obuhvaćene 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 "", 204import 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 na krajnje točke. Naslijeđeni webhook s jednim URL-om jedan je sinkroni pokušaj bez ponavljanja.
Ponovni pokušaji
Svaki se događaj pokušava isporučiti jednom odmah. Svaki odgovor 2xx
potvrđuje isporuku. Za svaki drugi ishod (koji nije 2xx,
pogreška veze, vremensko ograničenje) ponavljamo pokušaj 1 min, 5 min, 30 min, 2 h, 6 h,
12 h i 24 h nakon prvog pokušaja — 8 pokušaja tijekom
24 sata. Ako svaki pokušaj ne uspije, isporuka se zaustavlja, a krajnja točka
označava se kao status="failing" u
krajnjim točkama webhooka. Vratite 2xx čim je
payload trajno prihvaćen; obradite ga asinkrono.
Redoslijed
Redoslijed isporuke temelji se na najboljem mogućem nastojanju. U praksi isporučujemo redoslijedom
kojim se događaji emitiraju, 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 nikada
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 za krajnje točke — dvije krajnje točke pretplaćene na
isti događaj primaju isti event_id.
Vremenska ograničenja
Isporuke na krajnje točke imaju vremensko ograničenje od 30 s po pokušaju. Na
naslijeđenoj putanji, blokirajući zahtjevi koji upravljaju ponašanjem aktivnog poziva —
razmjena konfiguracije telephony.incoming / web.incoming —
istječu nakon 10 s, ali spor odgovor odgađa javljanje na poziv, stoga
odgovorite u roku od nekoliko sekundi. Slanje alata u načinu webhooka
slanje alata prema zadanim postavkama dopušta 20 s,
a deklaracije alata mogu postaviti timeout na najvišoj razini.
Izvorne IP adrese
Odlazni webhookovi dolaze iz raspona IP adresa ThunderPhone clouda. 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čajka | Naslijeđeni (/v1/webhook) | Krajnje točke (/v1/developer/webhook-endpoints) |
|---|---|---|
| Broj URL-ova | 1 po organizaciji | Više po organizaciji |
| Obuhvat događaja | Samo telephony.* / web.* | Svih 10 vrsta događaja |
| Filtar događaja | — | Po krajnjoj točki |
| Ponovni pokušaji | Nema | 8 pokušaja tijekom 24 h |
| Omotnica | type + data | type + data + event_id |
| Rotacija tajne | Zamjenjuje jednu tajnu | Tajna po krajnjoj točki |
| Onemogućavanje bez brisanja | PUT /v1/webhook s {"url": ""} | status=disabled |
| Vidljivost statusa | — | active / disabled / failing |
| Blokirajuća razmjena konfiguracije | Da (telephony.incoming / web.incoming) | Nikada — samo obavijesti |
| Najbolje za | Dinamičku konfiguraciju poziva | Korištenje 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 dinamički konfigurirate pozive u trenutku javljanja ili koristite slanje alata u načinu webhooka — te razmjene zahtjeva i odgovora rade samo na naslijeđenoj putanji.
Povezano
Sve vrste događaja i njihovi payloadovi.
Upravljajte višestrukim krajnjim točkama, filtrima događaja i tajnama.
Blokirajući zahtjev na koji vaš poslužitelj mora odgovoriti kako bi konfigurirao pozive.
Payload nakon poziva s transkriptom, snimkom i metrikama.