telephony.complete / web.complete
Tukio la ukamilishaji hutokea baada ya kila simu kuisha — simu za ndani, simu za nje, simu za wavuti, au simu za majaribio (kipindi cha maikrofoni cha builder). Halizuii utekelezaji: jibu kwa 2xx yoyote.
Tukio linawasilishwa kwenye njia zote mbili:
- Vituo vya webhook hupokea
telephony.complete(simu za simu) auweb.complete(simu za wavuti na simu za majaribio ya maikrofoni ya builder) zikiwa na payload thabiti iliyoelezewa hapa chini,event_idkwa kila uwasilishaji, muda wa kuisha wa s 30, na majaribio tena kwa hadi saa 24. - Webhook ya urithi yenye URL moja hupokea jaribio moja la usawazishaji (muda wa kuisha wa s 10, hakuna majaribio tena) lenye payload tofauti kidogo — tazama Tofauti za payload ya urithi.
Payload ya ombi (uwasilishaji wa endpoint)
{
"data": {
"billable_minutes": 1.25,
"billing_total_cents": 8,
"call_id": 987654321,
"direction": "inbound",
"duration_seconds": 54,
"end_reason": "user_hangup",
"end_time": "2026-04-20T18:25:04.822Z",
"from_number": "+14155550199",
"product": "spark",
"recording_url": "https://storage.example.com/…",
"start_time": "2026-04-20T18:24:10.113Z",
"status": "completed",
"to_number": "+15551234567",
"transcripts": [ /* see Transcript format */ ],
"transfer_number": null,
"voice": "john"
},
"event_id": "6a7b8c9d-0e1f-4a2b-8c3d-4e5f6a7b8c9d",
"type": "telephony.complete"
}
| Sehemu | Aina | Maelezo |
|---|---|---|
call_id | integer | Thabiti katika kila tukio la simu hii |
direction | string | inbound, outbound, web, test. Payload za kihistoria zinaweza kuwa na thamani za urithi za mic au widget |
from_number, to_number | string | E.164. from_number ni "web" halisi kwa simu za wavuti na simu za majaribio |
origin_domain | string | Kwa wavuti/majaribio pekee — origin ya ukurasa uliopangisha widget (tupu kwa vipindi vya maikrofoni) |
start_time, end_time | timestamp | ISO 8601 UTC |
duration_seconds | integer | null | Hutolewa kutoka muda wa kuanza/kuisha |
status | string | completed au failed |
end_reason | string | Tazama jedwali hapa chini |
product, voice | string | Usanidi wa ejenti uliokuwa unatumika wakati wa simu |
transfer_number | string | null | Huwekwa simu ilipohamishwa |
recording_url | string | null | URL iliyosainiwa inayokwisha muda; pakua mapema. null wakati hakuna rekodi inayopatikana |
billable_minutes | number | Dakika zinazotozwa, zikizungushwa hadi robo dakika iliyo karibu zaidi (ongezeko la sekunde 15, kiwango cha chini 0.25). Simu zinazoelekezwa moja kwa moja kwa voicemail bado huripoti dakika zake halisi zilizopimwa hapa, lakini malipo yanawekewa kikomo cha dakika moja kwa kiwango cha mpango. |
billing_total_cents | integer | Senti za USD |
transcripts | array | Ingizo za transkripti kwa kila zamu; zinaweza kuwa tupu wakati transkripti haipatikani |
Sababu za kuisha
| Thamani | Maana |
|---|---|
user_hangup | Mhusika wa mbali alikata simu kwanza |
ai_hangup | AI ilimaliza simu kimakusudi |
ai_transfer | AI ilihamisha simu; transfer_number imewekwa |
ai_warm_transfer | AI ilikamilisha uhamisho wa warm (wenye mhudhuriaji) |
voicemail_hangup | Voicemail ilitambuliwa na simu ikaisha kulingana na voicemail_action yako |
max_duration | Simu ilifikia kikomo cha muda wa juu zaidi |
superseded | Kipindi kilibadilishwa na kipya zaidi |
unknown | Sababu ya kuisha haikuweza kubainishwa |
Muundo wa transkripti
Kila ingizo katika transcripts ni zamu moja ya mazungumzo. Majukumu ni
user (usemi wa mpigaji simu), model (usemi wa ejenti na miito ya zana),
tool (matokeo ya zana), na system (matukio ya simu kama vile kubadilisha
lugha).
[
{
"role": "user",
"content_type": "text/plain",
"content": "Hi, I'm calling about my appointment.",
"start_ms": 1200,
"end_ms": 4100,
"audio_url": "https://storage.example.com/…"
},
{
"role": "model",
"content_type": "text/plain",
"content": "Sure, what date works best?",
"start_ms": 4200,
"end_ms": 6100
},
{
"role": "model",
"content_type": "application/json",
"content": {
"tool_call": "search_appointments",
"arguments": { "date": "2026-04-21" }
}
},
{
"role": "tool",
"content_type": "application/json",
"content": {
"tool_name": "search_appointments",
"response": { "available_slots": ["9:00 AM", "2:00 PM"] }
}
}
]
| Sehemu | Aina | Maelezo |
|---|---|---|
role | string | user, model, tool, au system |
content_type | string | text/plain kwa usemi; application/json kwa miito ya zana, matokeo ya zana na matukio ya mfumo |
content | string | object | Maandishi ya usemi, au kitu kilichoundwa kinachoonyeshwa hapo juu. Miito ya zana: {"tool_call": name, "arguments": {…}}. Matokeo ya zana: {"tool_name": name, "response": {…}} |
start_ms, end_ms | integer | Vipindi kuanzia simu ilipoanza, kwa ms. Huwepo wakati muda wa sauti unajulikana |
ttfa_ms | integer | Muda hadi sauti ya kwanza kwa zamu ya model, inapopimwa |
audio_url, audio_urls | string / array | URL zilizotiwa sahihi na muda wa kuisha za sauti ya zamu, sauti inaporekodiwa kwa kila zamu |
Kwa historia kamili ya zamu iliyoundwa (yenye alama za kukatiza,
prompt za uthibitisho, na nafasi ghafi), tumia
GET /v1/calls/{call_id}/history.
Tofauti za payload za urithi
Bahasha ya webhook ya urithi yenye URL moja ni
{"type": "telephony.complete" | "web.complete", "data": {…}} bila
event_id, na data yake inatofautiana na payload ya endpoint:
- Mpangilio wa zamu uko chini ya
history, sitranscripts(schema sawa ya zamu kama ilivyo hapo juu). - Seti ya sehemu ni ripoti ghafi ya mwisho wa simu na inaweza kujumuisha sehemu za ziada za ndani zaidi ya jedwali lililo hapo juu — chukulia sehemu zisizojulikana kama za taarifa.
- Simu za wavuti (
direction: "web") hazijumuishifrom_number/to_numberna huongezaorigin_domain. - Simu za majaribio ya maikrofoni ya Builder huripotiwa kama
telephony.completekwenye njia ya urithi (mfumo wa endpoint huzitafsiri kamaweb.complete). - Uratibu wa uhamisho: simu inapomalizika kwa uhamisho, webhook ya
urithi huitwa kwa usawazishaji na inaweza kujibu
{"transfer_ready": false}kuashiria kuwa lengwa la uhamisho haliko tayari. Jibu lingine lolote (au kutokuwepo kwa webhook ya urithi) huruhusu uhamisho kuendelea. Uwasilishaji wa endpoint hauangaliwi kamwe kwa hili.
Kishughulikiaji wa mfano
import hashlib
import hmac
import json
import os
from fastapi import FastAPI, HTTPException, Request
app = FastAPI()
SECRET = os.environ["THUNDERPHONE_WEBHOOK_SECRET"]
def verify(body: bytes, signature: str) -> bool:
expected = hmac.new(SECRET.encode(), body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, signature or "")
@app.post("/thunderphone-webhook")
async def webhook(request: Request):
body = await request.body()
if not verify(body, request.headers.get("X-ThunderPhone-Signature", "")):
raise HTTPException(status_code=401)
event = json.loads(body)
if event["type"] in ("telephony.complete", "web.complete"):
data = event["data"]
# Endpoint deliveries use "transcripts"; the legacy webhook uses "history".
turns = data.get("transcripts") or data.get("history") or []
await persist_call_record(
call_id=data["call_id"],
turns=turns,
recording_url=data.get("recording_url"),
)
if data["end_reason"] in ("ai_transfer", "ai_warm_transfer"):
await notify_team(data.get("transfer_number"), data["call_id"])
return {"ok": True}
import crypto from "node:crypto";
import express from "express";
const app = express();
const SECRET = process.env.THUNDERPHONE_WEBHOOK_SECRET;
function verify(body, signature) {
const expected = crypto.createHmac("sha256", SECRET).update(body).digest("hex");
return signature &&
crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
}
app.post(
"/thunderphone-webhook",
express.raw({ type: "application/json" }),
async (req, res) => {
if (!verify(req.body, req.header("X-ThunderPhone-Signature"))) {
return res.sendStatus(401);
}
const event = JSON.parse(req.body.toString("utf8"));
if (["telephony.complete", "web.complete"].includes(event.type)) {
const data = event.data;
// Endpoint deliveries use "transcripts"; the legacy webhook uses "history".
const turns = data.transcripts ?? data.history ?? [];
await persistCallRecord({ ...data, turns });
if (["ai_transfer", "ai_warm_transfer"].includes(data.end_reason)) {
await notifyTeam(data.transfer_number, data.call_id);
}
}
res.json({ ok: true });
},
);
Matumizi ya kawaida
Hifadhi nakala ya maandishi ya kila simu pamoja na URL ya rekodi sambamba na rekodi za wateja wako.
Tiririsha nakala za maandishi kwenye pipeline kwa ajili ya uundaji wa mada, uchimbaji wa ishara za CSAT, au ufuatiliaji wa kiwango cha uhamisho.
Fungua simu katika zana ya QA kwa ukaguzi wa kibinadamu, au zipitishe kwenye modeli yako mwenyewe ya tathmini.
Arifu mwenzako wa timu wa kibinadamu wakati wa uhamisho / hitilafu.