Veebihaakide ülevaade
ThunderPhone saadab sinu serverisse HTTP POST päringuid, kui kõne ajal midagi
juhtub — sissetulev kõne algab, kõne lõpeb, hindamiskäitus valmib, häire
käivitub jne. On kaks edastusmudelit:
Mitu URL-i, lõpp-punktipõhised saladused, lõpp-punktipõhised sündmusefiltrid
ja automaatsed korduskatsed.
Halda GET/POST/PATCH/DELETE /v1/developer/webhook-endpoints abil.
Üks URL organisatsiooni kohta. Sisaldab kõne elutsükli sündmusi, sealhulgas
blokeerivaid seadistusvahetusi. Halda GET/PUT /v1/webhook abil.
Kõik kümme sündmusetüüpi sündmuste kataloogis
edastatakse veebikonksu lõpp-punktide kaudu. Kuus kõne elutsükli sündmust
(telephony.incoming, telephony.complete, telephony.tool,
web.incoming, web.complete, web.tool) saadetakse samuti
ühe URL-iga pärandveebikonksule — kui sul on nii pärand-URL kui ka
sobiv lõpp-punkt, saad sündmuse kätte mõlemat marsruuti pidi. Blokeeriv
käitumine (telephony.incoming / web.incoming seadistusvahetus
ja veebikonksurežiimi tööriista suunamine)
toimub ainult pärandmarsruudil; iga lõpp-punkti edastus on teavitus, millele
vastust ei oodata.
Andmekoormuse vorming
Lõpp-punkti edastus on JSON-objekt väljadega data, event_id ja
type:
{
"data": {
"call_id": 987654321,
"from_number": "+14155550199",
"to_number": "+15551234567"
},
"event_id": "3f6b2ad0-1c9e-4a57-9f2b-8f6f0f9d2f11",
"type": "telephony.incoming"
}
event_id on iga väljastatud sündmuse jaoks kordumatu. See on sama nii
korduskatsete kui ka iga sündmust vastuvõtva lõpp-punkti puhul — kasuta
seda deduplikeerimiseks.
Ühe URL-iga pärandveebikonks saadab sama type ja data, kuid
ilma event_id-ta:
{
"type": "telephony.incoming",
"data": { "call_id": 987654321, "from_number": "+14155550199", "to_number": "+15551234567" }
}
Edastamisel serialiseeritakse iga keha kanooniliselt — võtmed sorditakse tähestikulises järjekorras, tühikuid ei lisata, kodeering on UTF-8. Nendes dokumentides olevad vormindatud näited on ainult loetavuse huvides.
Sündmusetüüpide ja andmekoormuse väljade täieliku loendi leiad sündmuste kataloogist.
Allkirja kontrollimine
Iga päring sisaldab päises X-ThunderPhone-Signature HMAC-SHA256 allkirja, mis on arvutatud toore päringu
keha põhjal. Allkirjastamisvõti on lõpp-punkti secret (või pärandversiooni
edastuste korral sinu organisatsioonitaseme webhooki secret).
Sammud
- Loe toores päringu keha enne mis tahes parsimist.
- Arvuta
hmac_sha256(secret, body).hexdigest(). - Võrdle seda konstantse ajaga päisega
X-ThunderPhone-Signature.
Allkirjastame täpselt need baidid, mille edastame, ning need baidid on kanooniline JSON-i serialiseering (sorditud võtmed, kompaktsed eraldajad). Seega toore keha põhjal kontrollimine alati toimib — ja kui sinu raamistik annab sulle ainult parsitud JSON-i, tekitab selle uuesti serialiseerimine sorditud võtmete ja kompaktsete eraldajatega identsed baidid. Mõlemat viisi käsitletakse allkirjade kontrollimise juhendis.
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);
},
);
Edastamise semantika
Need semantikad kehtivad lõpp-punkti edastustele. Pärandina kasutatav ühe URL-iga veebikonks teeb ühe sünkroonse katse ilma korduskatseteta.
Korduskatsed
Iga sündmust proovitakse kohe üks kord. Iga 2xx vastus
kinnitab edastuse. Kõigi muude tulemuste korral (mitte-2xx,
ühenduse tõrge, ajalõpp) proovime uuesti 1 min, 5 min, 30 min, 2 h, 6 h,
12 h ja 24 h pärast esimest katset — 8 katset 24 tunni
jooksul. Kui kõik katsed ebaõnnestuvad, edastamine peatub ja lõpp-punkt
märgitakse olekuga status="failing"
veebikonksu lõpp-punktides. Tagasta 2xx niipea,
kui andmekoormus on püsivalt vastu võetud; töötle seda asünkroonselt.
Järjestus
Edastuste järjestus toimub parima võimaliku pingutuse alusel. Praktikas edastame sündmused
nende väljastamise järjekorras, kuid tõrke korral võivad korduskatsed järjekorda muuta.
Eemalda alati duplikaadid ja kooskõlasta andmed call_id / objekti ID järgi.
Duplikaadid
Edastamine toimub vähemalt üks kord: korduskatse pärast vastust, mida me ei
näinud, võib sündmuse duplitseerida. Iga korduskatse sisaldab sama
event_id, seega salvesta töödeldud ID-d ja jäta kordused vahele. event_id on
jagatud ka lõpp-punktide vahel — kaks sama sündmuse tellinud lõpp-punkti
saavad sama event_id.
Ajalõpud
Lõpp-punkti edastustel on iga katse ajalõpp 30 s. Pärandteel aeguvad
reaalajas kõne käitumist juhtivad blokeerivad päringud —
telephony.incoming / web.incoming
konfiguratsioonivahetus — 10 s pärast, kuid aeglane vastus lükkab
kõne vastuvõtmist edasi, seega püüa vastata mõne sekundi jooksul.
Veebikonksurežiimis tööriistade käivitamiseks on aega 20 s.
Lähte-IP-aadressid
Väljaminevad veebikonksud pärinevad ThunderPhone'i pilve IP-aadressivahemikust. Kui sinu tulemüür nõuab lubatud loendit, võta ühendust klienditoega ja jagame kehtivaid vahemikke.
Pärand- ja lõpp-punktipõhiste veebikonksude valimine
| Funktsioon | Pärand (/v1/webhook) | Lõpp-punktid (/v1/developer/webhook-endpoints) |
|---|---|---|
| URL-ide arv | 1 organisatsiooni kohta | Mitu organisatsiooni kohta |
| Sündmuste katvus | Ainult telephony.* / web.* | Kõik 10 sündmusetüüpi |
| Sündmuse filter | — | Lõpp-punkti kohta |
| Korduskatsed | Puuduvad | 8 katset 24 h jooksul |
| Ümbris | type + data | type + data + event_id |
| Salajase võtme roteerimine | Asendab ühe salajase võtme | Lõpp-punktipõhine salajane võti |
| Keelamine kustutamata | — | status=disabled |
| Oleku nähtavus | — | active / disabled / failing |
| Blokeeriv konfiguratsioonivahetus | Jah (telephony.incoming / web.incoming) | Mitte kunagi — ainult teavitused |
| Sobib kõige paremini | Kõnede dünaamiline seadistamine | Sündmuste tarbimine tootmiskeskkonnas |
Uued integratsioonid peaksid sündmusi vastu võtma lõpp-punktipõhiste veebikonksude kaudu. Hoia (või lisa) pärand-URL-i ainult siis, kui seadistad kõnesid dünaamiliselt kõne vastuvõtmise ajal või kasutad veebikonksurežiimis tööriistade käivitamist — need päringu/vastuse vahetused töötavad ainult pärandteel.
Seotud
Kõik sündmusetüübid ja nende andmekoormused.
Halda mitut lõpp-punkti, sündmuse filtreid ja salajasi võtmeid.
Blokeeriv päring, millele sinu server peab kõnede seadistamiseks vastama.
Kõnejärgne andmekoormus koos transkriptsiooni, salvestise ja mõõdikutega.