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:
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 upravljajte putem GET/PUT /v1/webhook.
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
- Pročitajte sirovo 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 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č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 | — | status=disabled |
| Vidljivost statusa | — | active / disabled / failing |
| Blokirajuća razmjena konfiguracije | Da (telephony.incoming / web.incoming) | Nikad — samo obavijesti |
| Najbolje za | Dinamičku konfiguraciju poziva | Primanje 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
Sve vrste događaja i njihovi podaci.
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.
Podaci nakon poziva s transkriptom, snimkom i metrikama.