Open in
Общ преглед на уебкуките
Как ThunderPhone доставя събития в реално време, как да проверявате подписи и как се сравняват наследеният и базираният на крайни точки модели за доставка.
ThunderPhone изпраща HTTP POST заявки към вашия сървър, когато по време на разговор
се случат събития — започва входящо обаждане, разговор приключва, изпълнение
за оценяване завършва, задейства се предупреждение и т.н. Има два модела
за доставяне:
Множество URL адреси, тайни за всяка крайна точка, филтри за събития за всяка крайна точка
и автоматични повторни опити.
Управлявайте чрез GET/POST/PATCH/DELETE /v1/developer/webhook-endpoints.
Един URL адрес за организация. Съдържа събитията от жизнения цикъл на разговора, включително
блокиращите обмени на конфигурация. Управлява се чрез GET/PUT /v1/webhook.
Всички десет типа събития в каталога на събитията се
доставят чрез webhook крайни точки. Шестте събития от жизнения цикъл на разговора
(telephony.incoming, telephony.complete, telephony.tool,
web.incoming, web.complete, web.tool) се изпращат също към
наследения webhook с един URL адрес — ако имате както наследен URL адрес, така и
съвпадаща крайна точка, получавате събитието и по двата пътя. Блокиращото
поведение (обменът на конфигурация за telephony.incoming / web.incoming
и изпращането на инструменти в режим webhook)
е налично единствено по наследения път; всяко доставяне до крайна точка е
известие без изчакване на отговор.
Формат на полезния товар
Доставките до крайни точки са 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 е уникален за всяко излъчено събитие. Той е идентичен при повторни опити
и за всяка крайна точка, която получава събитието — използвайте го за премахване на дубликати.
Наследеният webhook с един URL адрес изпраща същите type и data, но
без event_id:
{
"type": "telephony.incoming",
"data": { "call_id": 987654321, "from_number": "+14155550199", "to_number": "+15551234567" }
}При предаване по мрежата всяко тяло се сериализира канонично — ключовете са сортирани по азбучен ред, без празни интервали, в UTF-8. Примерите с форматиране в тази документация са само за по-лесно четене.
Вижте Каталога на събитията за пълния списък с типове събития и полета на полезния товар.
Проверка на подписа
Всяка заявка съдържа HMAC-SHA256 подпис върху суровото тяло на
заявката в заглавката X-ThunderPhone-Signature. Ключът за подписване е
secret на крайната точка (или secret на webhook на ниво организация за
наследени доставки).
Стъпки
- Прочетете суровото тяло на заявката преди какъвто и да е анализ.
- Изчислете
hmac_sha256(secret, body).hexdigest(). - Сравнете го в константно време със заглавката
X-ThunderPhone-Signature.
Подписваме точно байтовете, които изпращаме, а тези байтове са каноничната JSON сериализация (сортирани ключове, компактни разделители). Затова проверката спрямо суровото тяло винаги работи — а ако вашата рамка ви предоставя само анализиран JSON, повторното му сериализиране със сортирани ключове и компактни разделители създава идентични байтове. И двата подхода са описани в ръководството за проверка.
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);
},
);Семантика на доставянето
Тази семантика се прилага за доставки към крайни точки. Наследеният уебкук с един URL представлява един синхронен опит без повторения.
Повторения
Всеки тип събитие се опитва веднъж незабавно. Всеки отговор 2xx
потвърждава доставянето. При всеки друг резултат (не-2xx,
грешка при свързване, изчакване) опитваме отново 1 мин., 5 мин., 30 мин., 2 ч., 6 ч.,
12 ч. и 24 ч. след първия опит — 8 опита в рамките на
24 часа. Ако всеки опит е неуспешен, доставянето спира и крайната точка
се маркира със status="failing" в
крайните точки за уебкуки. Върнете 2xx веднага щом
полезният товар бъде надеждно приет; обработвайте асинхронно.
Подреждане
Подреждането на доставките се извършва с максимално усилие. На практика доставяме в
реда, в който се генерират събитията, но повторните опити могат да променят реда при неуспех.
Винаги премахвайте дубликатите и съгласувайте по call_id / id на обекта.
Дубликати
Доставянето е поне веднъж: повторен опит след отговор, който не сме
получили, може да дублира събитие. Всеки повторен опит съдържа същия
event_id, затова съхранявайте обработените id и пропускайте повторенията. event_id се
споделя и между крайните точки — две крайни точки, абонирани за едно и също
събитие, получават един и същ event_id.
Изчаквания
Доставките към крайни точки имат изчакване от 30 сек. за всеки опит. По
наследения път блокиращите заявки, които управляват поведението на разговори на живо — обменът за
конфигурация telephony.incoming / web.incoming —
изтичат след 10 сек., но бавният отговор забавя приемането на разговора, затова
се стремете да отговорите в рамките на няколко секунди. Извикването на инструменти в режим на уебкуки
позволява 20 сек. по подразбиране, а декларациите на инструменти могат да задават timeout от най-горно ниво.
Изходящи IP адреси
Изходящите уебкуки произхождат от диапазона облачни IP адреси на ThunderPhone. Ако защитната ви стена изисква списък с разрешени адреси, свържете се с поддръжката и ще споделим текущите диапазони.
Избор между наследени уебкуки и уебкуки, базирани на крайни точки
| Функция | Наследени (/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 само ако конфигурирате разговори динамично при приемане или използвате извикване на инструменти в режим на уебкуки — тези обмени заявка/отговор се изпълняват само по наследения път.
Свързани
Всички типове събития и техните полезни товари.
Управлявайте множество крайни точки, филтри за събития и тайни.
Блокиращата заявка, на която сървърът ви трябва да отговори, за да конфигурира разговори.
Полезен товар след разговор с транскрипция, запис и показатели.