Webhookų apžvalga
ThunderPhone siunčia HTTP POST užklausas į jūsų serverį, kai skambučio metu
įvyksta tam tikri veiksmai – pradedamas įeinantis skambutis, baigiamas skambutis, užbaigiama vertinimo
vykdymo užduotis, suveikia įspėjimas ir pan. Yra du pristatymo
modeliai:
Keli URL, atskiri kiekvieno galinio taško raktai, kiekvieno galinio taško įvykių filtrai
ir automatiniai pakartotiniai bandymai.
Valdykite naudodami GET/POST/PATCH/DELETE /v1/developer/webhook-endpoints.
Vienas URL vienai organizacijai. Perduoda skambučio ciklo įvykius, įskaitant
blokuojančius konfigūracijos mainus. Valdoma naudojant GET/PUT /v1/webhook.
Visi dešimt įvykių tipų įvykių kataloge pristatomi
per webhook galinius taškus. Šeši skambučio ciklo įvykiai
(telephony.incoming, telephony.complete, telephony.tool,
web.incoming, web.complete, web.tool) taip pat siunčiami į
pasenusį vieno URL webhook – jei turite ir pasenusį URL, ir atitinkamą
galinį tašką, įvykį gaunate abiem keliais. Blokavimo
veiksmai (telephony.incoming / web.incoming konfigūracijos
mainai ir webhook režimo
įrankių paskirstymas) vykdomi
išskirtinai pasenusiu keliu; kiekvienas pristatymas į galinį tašką yra
pranešimas, siunčiamas nelaukiant atsakymo.
Duomenų formato struktūra
Pristatymas į galinį tašką yra JSON objektas su data, event_id ir
type:
{
"data": {
"call_id": 987654321,
"from_number": "+14155550199",
"to_number": "+15551234567"
},
"event_id": "3f6b2ad0-1c9e-4a57-9f2b-8f6f0f9d2f11",
"type": "telephony.incoming"
}
event_id yra unikalus kiekvienam išsiųstam įvykiui. Jis nesikeičia per
pakartotinius bandymus ir visuose galiniuose taškuose, kurie gauna įvykį –
naudokite jį dublikatams pašalinti.
Pasenęs vieno URL webhook siunčia tuos pačius type ir data, bet
be event_id:
{
"type": "telephony.incoming",
"data": { "call_id": 987654321, "from_number": "+14155550199", "to_number": "+15551234567" }
}
Perduodant tinklu, kiekvienas turinys yra kanoniškai serializuojamas – raktai surikiuojami abėcėlės tvarka, be tarpų, UTF-8 koduote. Šioje dokumentacijoje pateikti išdėstyti pavyzdžiai skirti tik skaitomumui.
Visą įvykių tipų ir duomenų laukų sąrašą rasite įvykių kataloge.
Parašo patvirtinimas
Kiekvienoje užklausoje antraštėje X-ThunderPhone-Signature pateikiamas HMAC-SHA256 parašas, apskaičiuotas pagal neapdorotą užklausos
turinį. Pasirašymo raktas yra galinio taško secret (arba jūsų organizacijos lygio žiniatinklio kablio secret, skirtas senesniems
siuntimams).
Veiksmai
- Nuskaitykite neapdorotą užklausos turinį prieš bet kokį analizavimą.
- Apskaičiuokite
hmac_sha256(secret, body).hexdigest(). - Pastoviuoju laiku palyginkite su antrašte
X-ThunderPhone-Signature.
Pasirašome tiksliai tuos baitus, kuriuos perduodame, o tie baitai yra kanoninis JSON serializavimas (surikiuoti raktai, glausti skirtukai). Todėl patvirtinimas pagal neapdorotą turinį visada veikia — o jei jūsų sistema pateikia tik išanalizuotą JSON, pakartotinis jo serializavimas su surikiuotais raktais ir glaustais skirtukais sukuria identiškus baitus. Abu būdai aprašyti patvirtinimo vadove.
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);
},
);
Pristatymo semantika
Ši semantika taikoma pristatymams į galinius taškus. Senasis vieno URL žiniatinklio kabliukas yra vienas sinchroninis bandymas be pakartotinių bandymų.
Pakartotiniai bandymai
Kiekvienas įvykis iš karto bandomas pristatyti vieną kartą. Bet koks 2xx atsakymas
patvirtina pristatymą. Esant bet kokiai kitai baigčiai (ne 2xx,
ryšio klaida, laiko limitas), bandome dar kartą praėjus 1 min., 5 min., 30 min., 2 val., 6 val.,
12 val. ir 24 val. po pirmojo bandymo — iš viso 8 bandymai per
24 valandas. Jei nepavyksta kiekvieno bandymo, pristatymas sustabdomas, o galinis taškas
žiniatinklio kabliukų galiniuose taškuose pažymimas būsena
status="failing". Grąžinkite 2xx iškart, kai
naudingasis krovinys patikimai priimtas; apdorokite asinchroniškai.
Eiliškumas
Pristatymo eiliškumas užtikrinamas pagal geriausias pastangas. Praktikoje pristatome tokia
tvarka, kuria įvykiai sugeneruojami, tačiau nesėkmės atveju pakartotiniai bandymai gali pakeisti eilę.
Visada pašalinkite dublikatus ir sulyginkite pagal call_id / objekto id.
Dublikatai
Pristatymas vyksta bent kartą: pakartotinis bandymas po atsakymo, kurio
negavome, gali dubliuoti įvykį. Kiekvienas pakartotinis bandymas turi tą patį
event_id, todėl saugokite apdorotus id ir praleiskite pasikartojimus. event_id
taip pat bendrinamas tarp galinių taškų — du galiniai taškai, užsiprenumeravę
tą patį įvykį, gauna tą patį event_id.
Laiko limitai
Pristatymams į galinius taškus taikomas 30 s laiko limitas kiekvienam bandymui. Senajame
kelyje blokuojančių užklausų, kurios lemia tiesioginio skambučio veikimą —
telephony.incoming / web.incoming
konfigūracijos apsikeitimo — laiko limitas yra 10 s, tačiau lėtas
atsakymas atideda skambučio atsiliepimą, todėl siekite atsakyti per kelias
sekundes. Žiniatinklio kabliuko režimo įrankių iškvietimas leidžia 20 s.
Šaltinio IP adresai
Išeinantys žiniatinklio kabliukai siunčiami iš ThunderPhone debesijos IP adresų diapazono. Jei jūsų užkardai reikalingas leidžiamųjų sąrašas, susisiekite su palaikymo komanda ir mes pateiksime dabartinius diapazonus.
Pasirinkimas tarp senųjų ir galinių taškų žiniatinklio kabliukų
| Funkcija | Senasis (/v1/webhook) | Galiniai taškai (/v1/developer/webhook-endpoints) |
|---|---|---|
| URL skaičius | 1 organizacijai | Daug organizacijai |
| Įvykių aprėptis | Tik telephony.* / web.* | Visi 10 įvykių tipų |
| Įvykių filtras | — | Kiekvienam galiniam taškui |
| Pakartotiniai bandymai | Nėra | 8 bandymai per 24 val. |
| Apvalkalas | type + data | type + data + event_id |
| Slaptojo rakto keitimas | Pakeičia vieną slaptąjį raktą | Slaptasis raktas kiekvienam galiniam taškui |
| Išjungimas neištrinant | — | status=disabled |
| Būsenos matomumas | — | active / disabled / failing |
| Blokuojantis konfigūracijos apsikeitimas | Taip (telephony.incoming / web.incoming) | Niekada — tik pranešimai |
| Geriausiai tinka | Dinaminei skambučių konfigūracijai | Įvykių naudojimui produkcinėje aplinkoje |
Naujos integracijos turėtų naudoti įvykius per galinių taškų žiniatinklio kabliukus. Išlaikykite (arba pridėkite) senąjį URL tik jei dinamiškai konfigūruojate skambučius atsiliepimo metu arba naudojate žiniatinklio kabliuko režimo įrankių iškvietimą — šie užklausos / atsakymo apsikeitimai vykdomi tik senuoju keliu.
Susiję
Visi įvykių tipai ir jų naudingi kroviniai.
Valdykite kelis galinius taškus, įvykių filtrus ir slaptuosius raktus.
Blokuojanti užklausa, į kurią jūsų serveris turi atsakyti, kad sukonfigūruotų skambučius.
Po skambučio siunčiamas naudingasis krovinys su transkriptu, įrašu ir metrika.