Open in
Преглед вебхукова
Како ThunderPhone испоручује догађаје у реалном времену, како да верификујете потписе и како се пореде застарели модели испоруке и модели засновани на крајњим тачкама.
ThunderPhone шаље HTTP POST захтеве вашем серверу када се
догађаји дешавају током позива — започне се долазни позив, позив се заврши, покретање
оцењивања се доврши, активира се упозорење и тако даље. Постоје два модела
испоруке:
Више URL адреса, тајне по крајњој тачки, филтери догађаја по крајњој тачки
и аутоматски поновни покушаји.
Управљајте путем GET/POST/PATCH/DELETE /v1/developer/webhook-endpoints.
Један URL по организацији. Преноси догађаје животног циклуса позива, укључујући
блокирајуће размене конфигурације. Управља се путем GET/PUT /v1/webhook.
Сви наведени типови догађаја у каталогу догађаја
испоручују се путем крајњих тачака веб-хукова. Шест догађаја животног циклуса позива
(telephony.incoming, telephony.complete, telephony.tool,
web.incoming, web.complete, web.tool) такође се шаљу на
застарели веб-хук са једним URL-ом — ако имате и застарели URL и одговарајућу
крајњу тачку, примате догађај на обе путање. Блокирајуће
понашање (размена конфигурације telephony.incoming / web.incoming
и слање алата у режиму веб-хука
слање алата) постоји
искључиво на застарелој путањи; свака испорука крајњој тачки је
обавештење без чекања одговора.
Формат садржаја
Испоруке крајњим тачкама су JSON објекат са data, event_id и
type:
{
"data": {
"call_id": 987654321,
"from_number": "+14155550199",
"to_number": "+15551234567"
},
"event_id": "3f6b2ad0-1c9e-4a57-9f2b-8f6f0f9d2f11",
"type": "telephony.incoming"
}event_id је јединствен за сваки емитовани догађај. Идентичан је при поновним покушајима
и на свакој крајњој тачки која прими догађај — користите га за уклањање дупликата.
Застарели веб-хук са једним URL-ом шаље исти type и data, али
без event_id:
{
"type": "telephony.incoming",
"data": { "call_id": 987654321, "from_number": "+14155550199", "to_number": "+15551234567" }
}При преносу, сваки садржај се серијализује канонски — кључеви су сортирани по абецеди, без размака, у UTF-8 формату. Примери са форматираним увлачењем у овој документацији служе само ради читљивости.
Погледајте Каталог догађаја за комплетну листу типова догађаја и поља садржаја.
Верификација потписа
Сваки захтев садржи два потписа, оба HMAC-SHA256 са кључем secret
крајње тачке (или secret веб-хука на нивоу ваше организације за застареле
испоруке):
X-ThunderPhone-Signature-V2: t=<unix seconds>,v1=<hex>потписује временску ознаку, метод, путању и упит, као и сирово тело. Проверите овај потпис и одбијте захтеве чији јеtудаљен више од 5 минута од вашег сата, како пресретнути захтев не би могао касније да се понови. Поновни покушаји се поново потписују када се пошаљу.X-ThunderPhone-Signatureпотписује само сирово тело. И даље се шаље непромењен, како би постојећи верификатори наставили да раде.
Кораци
- Прочитајте заглавље, метод, необрађену путању и упит, као и необрађено тело пре било каквог рашчлањивања.
- Израчунајте хексадецимални HMAC-SHA256 за
<t>\n<METHOD>\n<path and query>\n<body>помоћу своје тајне. - Одбијте захтев ако
tодступа више од 300 секунди или ако се резултат не подудара саv1при поређењу у константном времену.
Тела су канонска JSON серијализација (сортирани кључеви, компактни раздвајачи), а потписујемо тачно бајтове које преносимо. Водич за верификацију садржи тачан потписани низ, обрађен пример, код без SDK-а и застарело заглавље.
from flask import Flask, abort, request
from thunderphone import verify_signature
app = Flask(__name__)
@app.post("/thunderphone-webhook")
def handle():
query = request.query_string.decode()
if not verify_signature(
request.headers.get("X-ThunderPhone-Signature-V2"),
secret=WEBHOOK_SECRET,
method=request.method,
path=request.path + (f"?{query}" if query else ""),
body=request.get_data(), # raw bytes
):
abort(401)
event = request.get_json()
# dispatch on event["type"] …
return "", 204import express from "express";
import { verifySignature } from "@thunderphone/sdk";
const app = express();
app.post(
"/thunderphone-webhook",
express.raw({ type: "application/json" }),
(req, res) => {
const ok = verifySignature({
header: req.header("X-ThunderPhone-Signature-V2"),
secret: process.env.WEBHOOK_SECRET,
method: req.method,
path: req.originalUrl,
body: req.body,
});
if (!ok) return res.sendStatus(401);
const event = JSON.parse(req.body.toString("utf8"));
// dispatch on event.type …
res.sendStatus(204);
},
);Семантика испоруке
Ова семантика се примењује на испоруке крајњим тачкама. Застарели webhook са једним URL-ом
је један синхрони покушај без поновних покушаја, осим размене конфигурације
телефонског позива telephony.incoming,
за коју се покушај понавља једном.
Поновни покушаји
За сваки догађај се одмах прави један покушај. Сваки одговор 2xx
потврђује испоруку. За сваки други исход (одговор који није 2xx,
грешка везе, истек времена) понављамо покушај 1 m, 5 m, 30 m, 2 h, 6 h,
12 h и 24 h након првог покушаја — 8 покушаја током
24 часа. Ако сваки покушај не успе, испорука се прекида, а крајња тачка
се означава као status="failing" у
webhook крајњим тачкама; власницима и администраторима ваше организације
шаљемо е-поруку и приказујемо то на контролној табли. Вратите 2xx чим
је payload трајно прихваћен; обрађујте га асинхроно.
Пробна слања из API-ја за тестирање крајње тачке имају један поновни покушај приближно минут након
првог покушаја и никада не мењају статус крајње тачке.
Редослед
Редослед испоруке се обезбеђује у најбољој мери. У пракси испоручујемо редоследом
којим се догађаји емитују, али поновни покушаји могу променити редослед при неуспеху.
Увек уклањајте дупликате и усклађујте податке према call_id / ИД-у објекта.
Дупликати
Испорука је најмање једном: поновни покушај након одговора који никада
нисмо примили може дуплирати догађај. Сваки поновни покушај носи исти
event_id, зато чувајте обрађене ИД-ове и прескачите понављања. event_id се
такође дели између крајњих тачака — две крајње тачке претплаћене на исти
догађај примају исти event_id.
Истек времена
Испоруке крајњим тачкама имају истек времена од 30 s по покушају. На
застарелој путањи, блокирајући захтеви који управљају понашањем позива уживо — размена
конфигурације telephony.incoming / web.incoming —
ограничени су на 10 s за први покушај телефонског позива и 13 s
за целу размену, укључујући њен један поновни покушај, као и на 10 s
за сесију виџета. Спор одговор одлаже прихватање позива, зато настојте
да одговорите у року од неколико секунди. Отпремање алатки у webhook режиму
подразумевано дозвољава 20 s, а декларације алатки могу поставити timeout на највишем нивоу.
Изворне IP адресе
Одлазни вебхукови потичу из ThunderPhone опсега IP адреса у облаку. Ако ваш заштитни зид захтева листу дозвољених адреса, обратите се подршци и ми ћемо поделити тренутне опсеге.
Избор између застарелих вебхукова и вебхукова заснованих на крајњим тачкама
| Функција | Застарели (/v1/webhook) | Крајње тачке (/v1/developer/webhook-endpoints) |
|---|---|---|
| Број URL-ова | 1 по организацији | Више по организацији |
| Обухват догађаја | Само telephony.* / web.* | Свих 10 типова догађаја |
| Филтер догађаја | — | По крајњој тачки |
| Поновни покушаји | Нема, осим једног за размену конфигурације телефонског позива | 8 покушаја током 24 ч |
| Омотач | type + data | type + data + event_id |
| Ротација тајне | Замењује једну тајну | Тајна по крајњој тачки |
| Онемогућавање без брисања | PUT /v1/webhook са {"url": ""} | status=disabled |
| Видљивост статуса | — | active / disabled / failing |
| Блокирајућа размена конфигурације | Да (telephony.incoming / web.incoming) | Никада — само обавештења |
| Најбоље за | Динамичку конфигурацију позива | Коришћење догађаја у продукцији |
Нове интеграције треба да обрађују догађаје путем вебхукова заснованих на крајњим тачкама. Задржите (или додајте) застарели URL само ако конфигуришете позиве динамички у тренутку прихватања или користите покретање алатки у режиму вебхука — те размене захтева и одговора извршавају се само на застарелој путањи.
Повезано
Сви типови догађаја и њихови корисни терети.
Управљајте вишеструким крајњим тачкама, филтерима догађаја и тајнама.
Блокирајући захтев на који Ваш сервер мора да одговори да би конфигурисао позиве.
Корисни терет након позива са транскриптом, снимком и метрикама.