ThunderPhone 2.0 ir klāt.Sāciet uzreiz — no 2 centiem minūtē.Lasīt paziņojumu

Webhooks

Tīmekļa āķu pārskats

Kā ThunderPhone piegādā reāllaika notikumus, kā verificēt parakstus un kā salīdzināmi mantotais un galapunktos balstītais piegādes modelis.

ThunderPhone nosūta HTTP POST pieprasījumus uz jūsu serveri, kad zvana laikā notiek kāds notikums — sākas ienākošs zvans, zvans beidzas, tiek pabeigta novērtēšanas izpilde, tiek aktivizēts brīdinājums utt. Ir divi piegādes modeļi:

Visi desmit notikumu veidi notikumu katalogā tiek piegādāti, izmantojot tīmekļa aizķeru galapunktus. Seši zvana dzīves cikla notikumi (telephony.incoming, telephony.complete, telephony.tool, web.incoming, web.complete, web.tool) tiek arī nosūtīti uz mantoto tīmekļa aizķeri ar vienu URL — ja jums ir gan mantotais URL, gan atbilstošs galapunkts, notikumu saņemat pa abiem ceļiem. Bloķējošā darbība (telephony.incoming / web.incoming konfigurācijas apmaiņa un tīmekļa aizķera režīma rīku nosūtīšana) ir pieejama tikai mantotajā ceļā; katra piegāde uz galapunktu ir paziņojums bez atbildes gaidīšanas.

Lietderīgās slodzes formāts

Galapunktu piegādes ir JSON objekts ar data, event_id un type:

{
  "data": {
    "call_id": 987654321,
    "from_number": "+14155550199",
    "to_number": "+15551234567"
  },
  "event_id": "3f6b2ad0-1c9e-4a57-9f2b-8f6f0f9d2f11",
  "type": "telephony.incoming"
}

event_id ir unikāls katram izsūtītajam notikumam. Tas ir identisks atkārtotos mēģinājumos un visos galapunktos, kas saņem notikumu — izmantojiet to dublikātu novēršanai.

Mantotais tīmekļa aizķeris ar vienu URL nosūta to pašu type un data, bet bez event_id:

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

Pārsūtē katrs pamatteksts tiek serializēts kanoniski — atslēgas sakārtotas alfabētiski, bez atstarpēm, UTF-8. Šajā dokumentācijā glīti formatētie piemēri ir paredzēti tikai lasāmībai.

Skatiet Notikumu katalogu, lai iegūtu pilnu notikumu veidu un lietderīgās slodzes lauku sarakstu.

Paraksta verifikācija

Katram pieprasījumam galvenē X-ThunderPhone-Signature ir HMAC-SHA256 paraksts pār neapstrādāto pieprasījuma pamattekstu. Parakstīšanas atslēga ir galapunkta secret (vai jūsu organizācijas līmeņa tīmekļa aizķeres secret mantotajām piegādēm).

Darbības

  1. Nolasiet neapstrādāto pieprasījuma pamattekstu pirms jebkādas parsēšanas.
  2. Aprēķiniet hmac_sha256(secret, body).hexdigest().
  3. Salīdziniet to ar galveni X-ThunderPhone-Signature konstantā laikā.

Mēs parakstām tieši baitus, ko nosūtām, un šie baiti ir kanoniskā JSON serializācija (sakārtotas atslēgas, kompakti atdalītāji). Tāpēc verifikācija pret neapstrādāto pamattekstu vienmēr darbojas — un, ja jūsu ietvars nodod tikai parsētu JSON, tā atkārtota serializēšana ar sakārtotām atslēgām un kompaktiem atdalītājiem rada identiskus baitus. Abas metodes ir aprakstītas verifikācijas ceļvedī.

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);
  },
);

Piegādes semantika

Šī semantika attiecas uz galapunktu piegādēm. Mantotais viena URL webhook ir viens sinhrons mēģinājums bez atkārtotiem mēģinājumiem.

Atkārtoti mēģinājumi

Katrs notikums tiek mēģināts piegādāt vienu reizi nekavējoties. Jebkura 2xx atbilde apstiprina piegādi. Jebkura cita iznākuma gadījumā (ne-2xx, savienojuma kļūda, taimauts) mēs atkārtoti mēģinām pēc 1 min, 5 min, 30 min, 2 h, 6 h, 12 h un 24 h pēc pirmā mēģinājuma — 8 mēģinājumi 24 stundu laikā. Ja visi mēģinājumi neizdodas, piegāde tiek pārtraukta un galapunkts webhook galapunktos tiek atzīmēts ar status="failing". Atgrieziet 2xx, tiklīdz datu pakotne ir droši saglabāta; apstrādājiet to asinhroni.

Secība

Piegādes secība tiek nodrošināta pēc iespējas. Praksē mēs piegādājam notikumus to izraisīšanas secībā, taču neveiksmju gadījumā atkārtoti mēģinājumi var mainīt secību. Vienmēr noņemiet dublikātus un saskaņojiet pēc call_id / objekta id.

Dublikāti

Piegāde ir vismaz vienreiz: atkārtots mēģinājums pēc atbildes, kuru mēs nesaņēmām, var dublēt notikumu. Katrs atkārtotais mēģinājums ietver to pašu event_id, tāpēc saglabājiet apstrādātos id un izlaidiet atkārtojumus. event_id tiek koplietots arī starp galapunktiem — divi galapunkti, kas abonē vienu un to pašu notikumu, saņem vienādu event_id.

Taimauti

Galapunktu piegādēm katram mēģinājumam ir 30 s taimauts. Mantotajā ceļā bloķējošie pieprasījumi, kas nosaka aktīva zvana darbību — telephony.incoming / web.incoming konfigurācijas apmaiņa — sasniedz taimautu pēc 10 s, taču lēna atbilde aizkavē zvana pieņemšanu, tāpēc centieties atbildēt dažu sekunžu laikā. Webhook režīma rīku izsaukšana pēc noklusējuma atļauj 20 s, un rīku deklarācijas var iestatīt augstākā līmeņa timeout.

Avota IP adreses

Izejošie webhooki tiek sūtīti no ThunderPhone mākoņa IP diapazona. Ja jūsu ugunsmūrim nepieciešams atļauju saraksts, sazinieties ar atbalsta dienestu, un mēs kopīgosim aktuālos diapazonus.

Izvēle starp mantotajiem un uz galapunktiem balstītajiem webhookiem

FunkcijaMantotais (/v1/webhook)Galapunkti (/v1/developer/webhook-endpoints)
URL skaits1 katrai organizācijaiVairāki katrai organizācijai
Notikumu pārklājumsTikai telephony.* / web.*Visi 10 notikumu tipi
Notikumu filtrsKatram galapunktam
Atkārtoti mēģinājumiNav8 mēģinājumi 24 h laikā
Aploksnetype + datatype + data + event_id
Slepenās atslēgas rotācijaAizstāj vienoto slepeno atslēguSlepenā atslēga katram galapunktam
Deaktivizēšana bez dzēšanasstatus=disabled
Statusa redzamībaactive / disabled / failing
Bloķējoša konfigurācijas apmaiņaJā (telephony.incoming / web.incoming)Nekad — tikai paziņojumi
VispiemērotākaisDinamiska zvanu konfigurēšanaNotikumu apstrāde produkcijas vidē

Jaunām integrācijām notikumi jāsaņem, izmantojot uz galapunktiem balstītus webhookus. Saglabājiet (vai pievienojiet) mantoto URL tikai tad, ja konfigurējat zvanus dinamiski zvana pieņemšanas laikā vai izmantojat webhook režīma rīku izsaukšanu — šīs pieprasījuma/atbildes apmaiņas darbojas tikai mantotajā ceļā.


Saistīts