ThunderPhone 2.0 jau čia.Viską atlikite savarankiškai – nuo 2 ct/min.Skaityti pranešimą

Webhooks

Webhook apžvalga

Kaip ThunderPhone pateikia įvykius realiuoju laiku, kaip patikrinti parašus ir kuo skiriasi senasis bei galinio taško pagrindu veikiantys pateikimo modeliai.

ThunderPhone siunčia HTTP POST užklausas į jūsų serverį, kai skambučio metu įvyksta tam tikri veiksmai — prasideda įeinantis skambutis, baigiasi skambutis, užbaigiamas vertinimo vykdymas, suveikia įspėjimas ir pan. Yra du pristatymo modeliai:

Visi dešimt įvykių tipų, pateiktų įvykių kataloge, pristatomi per žiniatinklio kabliuko 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 į senąjį vienos URL žiniatinklio kabliuką — jei turite ir senąją URL, ir atitinkamą galinį tašką, įvykį gaunate abiejais keliais. Blokavimo veikimas ( telephony.incoming / web.incoming konfigūracijos mainai ir žiniatinklio kabliuko režimo įrankių iškvietimas) galimas tik senuoju keliu; kiekvienas pristatymas į galinį tašką yra pranešimas, kuriam atsakymo nelaukiama.

Naudingosios apkrovos formatas

Į galinius taškus pristatoma 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 sugeneruotam įvykiui. Jis yra toks pats per pakartotinius bandymus ir visuose galiniuose taškuose, kurie gauna įvykį — naudokite jį dublikatams pašalinti.

Senasis vienos URL žiniatinklio kabliukas siunčia tuos pačius type ir data, tačiau be event_id:

{
  "type": "telephony.incoming",
  "data": { "call_id": 987654321, "from_number": "+14155550199", "to_number": "+15551234567" }
}

Perduodant tinklu, kiekvienas užklausos turinys serializuojamas kanoniškai — raktai surūšiuojami abėcėlės tvarka, nėra tarpų, naudojamas UTF-8. Šiuose dokumentuose pateikti skaitymui suformatuoti pavyzdžiai skirti tik aiškumui.

Visą įvykių tipų ir naudingosios apkrovos 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 organizacijos lygio webhook secret, skirtas senesniems pristatymams).

Veiksmai

  1. Perskaitykite neapdorotą užklausos turinį prieš bet kokį analizavimą.
  2. Apskaičiuokite hmac_sha256(secret, body).hexdigest().
  3. 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, kompaktiški 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 kompaktiškais skirtukais sukuria identiškus baitus. Abu būdai aprašyti patvirtinimo vadove.

Python
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
Node.js (Express)
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 galinio punkto pristatymams. Senasis vieno URL žiniatinklio kabliukas yra vienas sinchroninis bandymas be pakartotinių bandymų.

Pakartotiniai bandymai

Kiekvienas įvykis iškart bandomas pristatyti vieną kartą. Bet koks 2xx atsakymas patvirtina pristatymą. Esant bet kokiai kitai baigčiai (ne 2xx, ryšio klaidai, laiko limitui), bandome dar kartą po 1 min., 5 min., 30 min., 2 val., 6 val., 12 val. ir 24 val. nuo pirmojo bandymo — iš viso 8 bandymai per 24 valandas. Jei nepavyksta visiems bandymams, pristatymas sustabdomas, o galinis punktas žiniatinklio kabliukų galiniuose punktuose pažymimas būsena status="failing". Grąžinkite 2xx iškart, kai naudingasis krovinys patikimai priimamas; apdorokite jį asinchroniškai.

Eiliškumas

Pristatymo eiliškumas užtikrinamas dedant visas pastangas. Praktikoje pristatome tokia tvarka, kuria įvykiai sugeneruojami, tačiau nepavykus bandymams pakartotiniai bandymai gali pakeisti eilę. Visada šalinkite dublikatus ir sutaikykite pagal call_id / objekto ID.

Dublikatai

Pristatymas yra 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ų punktų — du galiniai punktai, užsiprenumeravę tą patį įvykį, gauna tą patį event_id.

Laiko limitai

Galinių punktų pristatymams taikomas 30 s laiko limitas kiekvienam bandymui. Senajame kelyje blokuojančios užklausos, lemiančios tiesioginio skambučio veikimą — telephony.incoming / web.incoming konfigūracijos apsikeitimas — baigia galioti po 10 s, tačiau lėtas atsakymas vėlina skambučio priėmimą, todėl siekite atsakyti per kelias sekundes. Žiniatinklio kabliuko režimo įrankių iškvietimas pagal numatytuosius nustatymus leidžia 20 s, o įrankių deklaracijose galima nustatyti aukščiausio lygio timeout.

Šaltinio IP adresai

Siunčiami žiniatinklio kabliukai gaunami iš ThunderPhone debesijos IP adresų diapazono. Jei jūsų užkarda reikalauja leidžiamųjų sąrašo, susisiekite su palaikymo komanda ir pateiksime aktualius diapazonus.

Pasirinkimas tarp senųjų ir galinių punktų pagrindu veikiančių žiniatinklio kabliukų

FunkcijaSenasis (/v1/webhook)Galiniai punktai (/v1/developer/webhook-endpoints)
URL skaičius1 vienai organizacijaiKeli vienai organizacijai
Įvykių aprėptisTik telephony.* / web.*Visi 10 įvykių tipų
Įvykių filtrasKiekvienam galiniam punktui
Pakartotiniai bandymaiNėra8 bandymai per 24 val.
Vokastype + datatype + data + event_id
Slaptojo rakto keitimasPakeičia vieną slaptąjį raktąSlaptasis raktas kiekvienam galiniam punktui
Išjungimas neištrinantPUT /v1/webhook su {"url": ""}status=disabled
Būsenos matomumasactive / disabled / failing
Blokuojantis konfigūracijos apsikeitimasTaip (telephony.incoming / web.incoming)Niekada — tik pranešimai
Geriausia naudotiDinaminei skambučių konfigūracijaiĮvykių vartojimui produkcinėje aplinkoje

Naujose integracijose įvykius reikėtų vartoti per galinių punktų pagrindu veikiančius žiniatinklio kabliukus. Senąjį URL palikite (arba pridėkite) tik jei dinamiškai konfigūruojate skambučius jų priėmimo metu arba naudojate žiniatinklio kabliuko režimo įrankių iškvietimą — šie užklausos ir atsakymo apsikeitimai vykdomi tik senuoju keliu.


Susiję