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:
Useita URL-osoitteita, päätepistekohtaiset salaisuudet, päätepistekohtaiset tapahtumasuodattimet
ja automaattiset uudelleenyritykset.
Hallitse käyttämällä GET/POST/PATCH/DELETE /v1/developer/webhook-endpoints.
Yksi URL-osoite organisaatiota kohden. Sisältää puhelun elinkaaren tapahtumat, mukaan lukien
estävät määritysvaihdot. Hallitse käyttämällä GET/PUT /v1/webhook.
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
- Lue raakapyynnön runko ennen jäsentämistä.
- Laske
hmac_sha256(secret, body).hexdigest(). - 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.
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 "", 204import 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
| Ominaisuus | Vanha (/v1/webhook) | Päätepisteet (/v1/developer/webhook-endpoints) |
|---|---|---|
| URL-osoitteiden määrä | 1 organisaatiota kohden | Useita organisaatiota kohden |
| Tapahtumakattavuus | Vain telephony.* / web.* | Kaikki 10 tapahtumatyyppiä |
| Tapahtumasuodatin | — | Päätepistekohtainen |
| Uudelleenyritykset | Ei mitään | 8 yritystä 24 tunnin aikana |
| Kirjekuori | type + data | type + data + event_id |
| Salaisuuden kierto | Korvaa yhden salaisuuden | Päätepistekohtainen salaisuus |
| Käytöstäpoisto poistamatta | — | status=disabled |
| Tilan näkyvyys | — | active / disabled / failing |
| Estävä määrityspyyntö-vastausvaihto | Kyllä (telephony.incoming / web.incoming) | Ei koskaan — vain ilmoituksia |
| Sopii parhaiten | Dynaamiseen puhelumääritykseen | Tapahtumien 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ää
Kaikki tapahtumatyypit ja niiden hyötykuormat.
Hallitse useita päätepisteitä, tapahtumasuodattimia ja salaisuuksia.
Estävä pyyntö, johon palvelimesi on vastattava puhelujen määrittämiseksi.
Puhelun jälkeinen hyötykuorma, joka sisältää transkription, tallenteen ja mittarit.