ThunderPhone 2.0 este acum disponibil.Self-service, de la 2 ¢/min.Citiți anunțul

Webhooks

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:

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ăror t diferă 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-Signature semnează numai corpul brut. Este trimisă în continuare, nemodificată, astfel încât verificatorii existenți să funcționeze în continuare.

Pași

  1. Citiți antetul, metoda, calea brută și interogarea, precum și corpul brut înainte de orice analiză.
  2. Calculați HMAC-SHA256 hexazecimal al <t>\n<METHOD>\n<path and query>\n<body> folosind secretul dumneavoastră.
  3. Respingeți solicitarea dacă t diferă cu mai mult de 300 de secunde sau dacă rezultatul nu corespunde cu v1 î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.

Python (Flask)
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 "", 204
Node.js (Express)
import 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ționalitateVersiune moștenită (/v1/webhook)Endpointuri (/v1/developer/webhook-endpoints)
Număr de URL-uri1 per organizațieMai multe per organizație
Acoperire evenimenteDoar telephony.* / web.*Toate cele 10 tipuri de evenimente
Filtru de evenimente—Per endpoint
ReîncercăriNiciuna, cu excepția uneia pentru schimbul de configurare a apelului telefonic8 încercări în 24 h
Plictype + datatype + data + event_id
Rotația secretuluiÎnlocuiește secretul unicSecret per endpoint
Dezactivare fără ștergerePUT /v1/webhook cu {"url": ""}status=disabled
Vizibilitatea stării—active / disabled / failing
Schimb de configurare blocantDa (telephony.incoming / web.incoming)Niciodată — doar notificări
Recomandat pentruConfigurarea dinamică a apelurilorConsumarea 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