ThunderPhone 2.0 on nyt julkaistu.Ota käyttöön itse – alkaen 2¢/min.Lue lisää julkistuksesta

Webhooks

Webhookien yleiskatsaus

Miten ThunderPhone toimittaa reaaliaikaisia tapahtumia, miten allekirjoitukset vahvistetaan ja miten vanha toimitusmalli vertautuu päätepistepohjaiseen toimitusmalliin.

ThunderPhone lähettää HTTP-POST-pyyntöjä palvelimellesi, kun puhelun aikana tapahtuu asioita — saapuva puhelu alkaa, puhelu päättyy, arviointiajo valmistuu, hälytys laukeaa ja niin edelleen. Käytössä on kaksi toimitusmallia:

Kaikki kymmenen tapahtumaluettelon tapahtumatyyppiä toimitetaan webhook-päätepisteiden kautta. Kuusi puhelun elinkaaren tapahtumaa (telephony.incoming, telephony.complete, telephony.tool, web.incoming, web.complete, web.tool) lähetetään myös vanhaan yhden URL-osoitteen webhookiin — jos sinulla on sekä vanha URL-osoite että vastaava päätepiste, saat tapahtuman molempia reittejä pitkin. Estävä toiminta (telephony.incoming / web.incoming -määritysvaihto ja webhook-tilan työkalun välitys) on käytettävissä vain vanhalla reitillä; jokainen päätepistetoimitus on ilmoitus ilman vastausta.

Hyötykuorman muoto

Päätepistetoimitukset ovat JSON-objekteja, joissa on 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 yksilöllinen jokaiselle lähetetylle tapahtumalle. Se on sama uudelleenyrityksissä ja kaikissa tapahtuman vastaanottavissa päätepisteissä — poista kaksoiskappaleet sen perusteella.

Vanha yhden URL-osoitteen webhook lähettää saman type- ja data-sisällön, mutta ilman event_id:tä:

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

Verkossa jokainen runko sarjoitetaan kanonisesti — avaimet lajitellaan aakkosjärjestykseen, välilyöntejä ei käytetä ja merkistönä on UTF-8. Näiden dokumenttien kauniisti muotoillut esimerkit ovat vain luettavuuden vuoksi.

Katso tapahtumaluettelosta täydellinen luettelo tapahtuma- tyypeistä ja hyötykuormakentistä.

Allekirjoituksen vahvistaminen

Jokainen pyyntö sisältää HMAC-SHA256-allekirjoituksen raakapyynnön rungosta X-ThunderPhone-Signature-otsakkeessa. Allekirjoitusavain on päätepisteen secret (tai organisaatiotason webhookin secret vanhoja toimituksia varten).

Vaiheet

  1. Lue raakapyynnön runko ennen jäsentämistä.
  2. Laske hmac_sha256(secret, body).hexdigest().
  3. Vertaa sitä vakioaikaisesti X-ThunderPhone-Signature-otsakkeeseen.

Allekirjoitamme täsmälleen lähettämämme tavut, ja nämä tavut ovat kanoninen JSON-sarjoitus (lajitellut avaimet, tiiviit erottimet). Siksi raakapyynnön runkoa vastaan vahvistaminen toimii aina — ja jos kehys antaa käyttöösi vain jäsennetyn JSONin, sen uudelleensarjoitus lajitelluilla avaimilla ja tiiviillä erottimilla tuottaa samat tavut. Molemmat menetelmät käsitellään vahvistusoppaassa.

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

Toimitussemantiikka

Nämä semantiikat koskevat päätepistetoimituksia. Vanha yhden URL-osoitteen webhook on yksi synkroninen yritys ilman uudelleenyrityksiä.

Uudelleenyritykset

Jokaista tapahtumaa yritetään toimittaa kerran välittömästi. Mikä tahansa 2xx-vastaus vahvistaa toimituksen. Kaikissa muissa tapauksissa (muu kuin 2xx, yhteysvirhe, aikakatkaisu) yritämme uudelleen 1 min, 5 min, 30 min, 2 h, 6 h, 12 h ja 24 h ensimmäisen yrityksen jälkeen — 8 yritystä 24 tunnin aikana. Jos kaikki yritykset epäonnistuvat, toimitus pysähtyy ja päätepiste merkitään tilaan status="failing" webhook-päätepisteissä. Palauta 2xx heti, kun hyötykuorma on vastaanotettu pysyvästi; käsittele se asynkronisesti.

Järjestys

Toimitusjärjestys on parhaaseen pyrkivä. Käytännössä toimitamme tapahtumat niiden lähetysjärjestyksessä, mutta uudelleenyritykset voivat muuttaa järjestystä virhetilanteissa. Poista aina kaksoiskappaleet ja täsmäytä call_id:n / objektitunnuksen perusteella.

Kaksoiskappaleet

Toimitus on vähintään kerran: uudelleenyritys vastauksen jälkeen, jota emme koskaan nähneet, voi tuottaa tapahtumasta kaksoiskappaleen. Jokaisella uudelleenyrityksellä on sama event_id, joten tallenna käsitellyt tunnukset ja ohita toistot. event_id on myös yhteinen päätepisteiden välillä — kaksi samaa tapahtumaa tilaavaa päätepistettä vastaanottaa saman event_id:n.

Aikakatkaisut

Päätepistetoimituksilla on 30 s:n aikakatkaisu jokaista yritystä kohden. Vanhalla polulla estävät pyynnöt, jotka ohjaavat käynnissä olevan puhelun toimintaa — telephony.incoming / web.incoming määrityspyyntö-vastausvaihto — aikakatkaistaan 10 s jälkeen, mutta hidas vastaus viivästyttää puheluun vastaamista, joten pyri vastaamaan muutamassa sekunnissa. Webhook-tilan työkalukutsujen välitys sallii oletuksena 20 s, ja työkalumääritykset voivat asettaa ylimmän tason timeout-arvon.

Lähde-IP-osoitteet

Lähtevät webhookit tulevat ThunderPhonen pilven IP-osoitealueelta. Jos palomuurisi edellyttää sallittujen osoitteiden luetteloa, ota yhteyttä tukeen, niin jaamme nykyiset alueet.

Vanhojen ja päätepistepohjaisten webhookien valitseminen

OminaisuusVanha (/v1/webhook)Päätepisteet (/v1/developer/webhook-endpoints)
URL-osoitteiden määrä1 organisaatiota kohdenUseita organisaatiota kohden
TapahtumakattavuusVain telephony.* / web.*Kaikki 10 tapahtumatyyppiä
TapahtumasuodatinPäätepistekohtainen
UudelleenyrityksetEi mitään8 yritystä 24 tunnin aikana
Kirjekuoritype + datatype + data + event_id
Salaisuuden kiertoKorvaa yhden salaisuudenPäätepistekohtainen salaisuus
Käytöstäpoisto poistamattastatus=disabled
Tilan näkyvyysactive / disabled / failing
Estävä määrityspyyntö-vastausvaihtoKyllä (telephony.incoming / web.incoming)Ei koskaan — vain ilmoituksia
Sopii parhaitenDynaamiseen puhelumääritykseenTapahtumien vastaanottamiseen tuotannossa

Uusien integraatioiden tulee vastaanottaa tapahtumat päätepistepohjaisten webhookien kautta. Säilytä (tai lisää) vanha URL-osoite vain, jos määrität puhelut dynaamisesti puheluun vastattaessa tai käytät webhook-tilan työkalukutsujen välitystä — nämä pyyntö-vastausvaihdot toimivat vain vanhalla polulla.


Aiheeseen liittyvää