Open in
Prezentare generală a webhookurilor
Cum livrează ThunderPhone evenimente în timp real, cum verificați semnăturile și cum se compară modelele de livrare vechi și bazate pe endpointuri.
ThunderPhone trimite cereri HTTP POST către serverul dumneavoastră atunci când se
întâmplă lucruri în timpul unui apel — începe un apel de intrare, se încheie un apel, se finalizează
o rulare de evaluare, se declanșează o alertă și așa mai departe. Există două modele
de livrare:
URL-uri multiple, secrete per endpoint, filtre de evenimente per endpoint
și reîncercări automate.
Gestionați prin GET/POST/PATCH/DELETE /v1/developer/webhook-endpoints.
Un URL per organizație. Include evenimentele din ciclul de viață al apelului, inclusiv
schimburile de configurare blocante. Gestionat prin GET/PUT /v1/webhook.
Toate tipurile de evenimente enumerate în catalogul de evenimente sunt
livrate prin endpointuri webhook. Cele șase evenimente din ciclul de viață al apelului
(telephony.incoming, telephony.complete, telephony.tool,
web.incoming, web.complete, web.tool) sunt trimise și către
webhookul legacy cu un singur URL — dacă aveți atât un URL legacy, cât și un
endpoint corespunzător, primiți evenimentul pe ambele căi. Comportamentul blocant
(schimbul de configurare telephony.incoming / web.incoming și
dispecerizarea instrumentelor în modul webhook)
există exclusiv pe calea legacy; fiecare livrare către endpoint este o
notificare fără așteptarea răspunsului.
Formatul încărcăturii utile
Livrările către endpointuri sunt un obiect JSON cu 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 este unic pentru fiecare eveniment emis. Este identic între reîncercări
și între toate endpointurile care primesc evenimentul — eliminați duplicatele pe baza acestuia.
Webhookul legacy cu un singur URL trimite aceleași valori type și data, însă
fără event_id:
{
"type": "telephony.incoming",
"data": { "call_id": 987654321, "from_number": "+14155550199", "to_number": "+15551234567" }
}În tranzit, fiecare corp este serializat canonic — cheile sunt sortate alfabetic, fără spații albe, în UTF-8. Exemplele formatate pentru afișare din această documentație sunt doar pentru lizibilitate.
Consultați Catalogul de evenimente pentru lista completă a tipurilor de evenimente și a câmpurilor încărcăturii utile.
Verificarea semnăturii
Fiecare cerere include două semnături, ambele HMAC-SHA256 cu cheia
secret a endpointului (sau secret webhook la nivel de organizație pentru
livrările vechi):
X-ThunderPhone-Signature-V2: t=<unix seconds>,v1=<hex>semnează marcajul temporal, metoda, calea și interogarea, precum și corpul brut. Verificați-o pe aceasta și respingeți cererile al cărortdiferă cu mai mult de 5 minute față de ceasul dumneavoastră, astfel încât o cerere capturată să nu poată fi redifuzată ulterior. Reîncercările sunt semnate din nou când sunt trimise.X-ThunderPhone-Signaturesemnează numai corpul brut. Este trimisă în continuare, nemodificată, astfel încât verificatorii existenți să funcționeze în continuare.
Pași
- Citiți antetul, metoda, calea brută și interogarea, precum și corpul brut înainte de orice analiză.
- Calculați HMAC-SHA256 hexazecimal al
<t>\n<METHOD>\n<path and query>\n<body>folosind secretul dumneavoastră. - Respingeți solicitarea dacă
tdiferă cu mai mult de 300 de secunde sau dacă rezultatul nu corespunde cuv1într-o comparare în timp constant.
Corpurile sunt serializarea JSON canonică (chei sortate, separatoare compacte) și semnăm exact octeții pe care îi transmitem. Ghidul de verificare conține șirul semnat exact, un exemplu detaliat, cod fără SDK și antetul vechi.
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 "", 204import 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);
},
);Semantica livrării
Aceste semantici se aplică livrărilor către endpoint. Webhookul moștenit cu un singur URL
este o singură încercare sincronă, fără reîncercări, cu excepția
schimbului de configurație pentru apeluri telefonice telephony.incoming,
care este reîncercat o dată.
Reîncercări
Fiecare eveniment este încercat imediat o dată. Orice răspuns 2xx
confirmă livrarea. Pentru orice alt rezultat (altul decât 2xx,
eroare de conexiune, expirare a timpului), reîncercăm la 1 min., 5 min., 30 min., 2 h, 6 h,
12 h și 24 h după prima încercare — 8 încercări pe durata a
24 de ore. Dacă toate încercările eșuează, livrarea se oprește, iar endpointul
este marcat cu status="failing" în
endpointurile webhook; trimitem un e-mail proprietarilor
și administratorilor organizației dumneavoastră și afișăm acest lucru în tabloul de bord. Returnați 2xx de îndată ce
încărcătura utilă este acceptată în mod durabil; procesați-o asincron.
Trimiterile de test din API-ul de testare a endpointului primesc o reîncercare la aproximativ un minut după
prima încercare și nu modifică niciodată starea endpointului.
Ordonare
Ordonarea livrărilor se face după principiul efortului maxim. În
practică, livrăm în ordinea în care sunt emise evenimentele, însă
reîncercările pot schimba ordinea în caz de eșec.
Eliminați întotdeauna duplicatele și reconciliați după call_id / id-ul obiectului.
Duplicate
Livrarea este cel puțin o dată: o reîncercare după un răspuns pe care nu l-am
primit poate duplica un eveniment. Fiecare reîncercare conține același
event_id, așadar stocați id-urile procesate și ignorați repetările. event_id este
partajat și între endpointuri — două endpointuri abonate la același
eveniment primesc același event_id.
Expirări ale timpului
Livrările către endpoint au o limită de timp de 30 s pentru fiecare încercare. Pe
calea moștenită, cererile blocante care controlează comportamentul apelurilor în timp real — schimbul de
configurație telephony.incoming / web.incoming
— sunt limitate la 10 s pentru prima încercare a unui apel telefonic
și la 13 s pentru întregul schimb, inclusiv unica sa
reîncercare, precum și la 10 s pentru o sesiune de widget. Un răspuns lent întârzie
preluarea apelului, astfel încât urmăriți să răspundeți în câteva secunde. Transmiterea instrumentelor în modul webhook permite 20 s
în mod implicit, iar declarațiile de instrumente pot seta un timeout de nivel superior.
IP-uri sursă
Webhookurile trimise provin din intervalul de IP-uri cloud al ThunderPhone. Dacă paravanul dumneavoastră de protecție necesită o listă de permisiuni, contactați asistența, iar noi vă vom comunica intervalele actuale.
Alegerea între webhookurile moștenite și cele bazate pe endpointuri
| Funcționalitate | Versiune moștenită (/v1/webhook) | Endpointuri (/v1/developer/webhook-endpoints) |
|---|---|---|
| Număr de URL-uri | 1 per organizație | Mai multe per organizație |
| Acoperire evenimente | Doar telephony.* / web.* | Toate cele 10 tipuri de evenimente |
| Filtru de evenimente | — | Per endpoint |
| Reîncercări | Niciuna, cu excepția uneia pentru schimbul de configurare a apelului telefonic | 8 încercări în 24 h |
| Plic | type + data | type + data + event_id |
| Rotația secretului | Înlocuiește secretul unic | Secret per endpoint |
| Dezactivare fără ștergere | PUT /v1/webhook cu {"url": ""} | status=disabled |
| Vizibilitatea stării | — | active / disabled / failing |
| Schimb de configurare blocant | Da (telephony.incoming / web.incoming) | Niciodată — doar notificări |
| Recomandat pentru | Configurarea dinamică a apelurilor | Consumarea evenimentelor în producție |
Integrările noi trebuie să consume evenimente prin webhookuri bazate pe endpointuri. Păstrați (sau adăugați) un URL moștenit numai dacă configurați apelurile dinamic în momentul preluării sau utilizați dispecerizarea instrumentelor în modul webhook — aceste schimburi cerere/răspuns funcționează numai pe ruta moștenită.
Asociate
Toate tipurile de evenimente și încărcăturile lor utile.
Gestionați mai multe endpointuri, filtre de evenimente și secrete.
Cererea blocantă la care serverul dumneavoastră trebuie să răspundă pentru a configura apelurile.
Încărcătură utilă post-apel cu transcriere, înregistrare și metrici.