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:

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

  1. Loe toores päringu keha enne mis tahes parsimist.
  2. Arvuta hmac_sha256(secret, body).hexdigest().
  3. 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

FunktsioonPärand (/v1/webhook)Lõpp-punktid (/v1/developer/webhook-endpoints)
URL-ide arv1 organisatsiooni kohtaMitu organisatsiooni kohta
Sündmuste katvusAinult telephony.* / web.*Kõik 10 sündmusetüüpi
Sündmuse filterLõpp-punkti kohta
KorduskatsedPuuduvad8 katset 24 h jooksul
Ümbristype + datatype + data + event_id
Salajase võtme roteerimineAsendab ühe salajase võtmeLõpp-punktipõhine salajane võti
Keelamine kustutamatastatus=disabled
Oleku nähtavusactive / disabled / failing
Blokeeriv konfiguratsioonivahetusJah (telephony.incoming / web.incoming)Mitte kunagi — ainult teavitused
Sobib kõige pareminiKõnede dünaamiline seadistamineSü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