telephony.complete / web.complete
ഓരോ കോൾ അവസാനിച്ചതിന് ശേഷവും ഒരു കമ്പ്ലീഷൻ ഇവന്റ് പ്രവർത്തിക്കും — ഇൻബൗണ്ട് ടെലിഫോണി, ഔട്ട്ബൗണ്ട് ടെലിഫോണി, വെബ് കോൾ, അല്ലെങ്കിൽ ടെസ്റ്റ് കോൾ (ബിൽഡർ മൈക്ക് സെഷൻ). ഇത് ബ്ലോക്ക് ചെയ്യാത്തതാണ്: ഏതെങ്കിലും 2xx ഉപയോഗിച്ച് പ്രതികരിക്കുക.
ഇവന്റ് രണ്ട് പാതകളിലും ഡെലിവർ ചെയ്യപ്പെടുന്നു:
- വെബ്ഹുക്ക് എൻഡ്പോയിന്റുകൾ ന്
telephony.complete(ഫോൺ കോളുകൾ) അല്ലെങ്കിൽweb.complete(വെബ് കോളുകളും ബിൽഡർ മൈക്ക് ടെസ്റ്റ് കോളുകളും) താഴെ ഡോക്യുമെന്റ് ചെയ്ത സ്ഥിരതയുള്ള പേലോഡോടൊപ്പം, ഓരോ ഡെലിവറിക്കും ഒരുevent_id, 30 സെക്കൻഡ് ടൈംഔട്ട്, കൂടാതെ 24 മണിക്കൂർ വരെയുള്ള റീട്രൈകൾ ലഭിക്കും. - ലെഗസി ഒറ്റ-URL വെബ്ഹുക്ക് അല്പം വ്യത്യസ്തമായ പേലോഡോടെ ഒരു സിൻക്രണസ് ശ്രമം (10 സെക്കൻഡ് ടൈംഔട്ട്, റീട്രൈകളില്ല) സ്വീകരിക്കും — ലെഗസി പേലോഡ് വ്യത്യാസങ്ങൾ കാണുക.
റിക്വസ്റ്റ് പേലോഡ് (എൻഡ്പോയിന്റ് ഡെലിവറികൾ)
{
"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"
}
| ഫീൽഡ് | തരം | വിവരണം |
|---|---|---|
call_id | integer | ഈ കോളിനുള്ള എല്ലാ ഇവന്റുകളിലും സ്ഥിരതയുള്ളത് |
direction | string | inbound, outbound, web, test. പഴയ പേലോഡുകളിൽ ലെഗസി mic അല്ലെങ്കിൽ widget മൂല്യങ്ങൾ ഉണ്ടായേക്കാം |
from_number, to_number | string | E.164. വെബ് കോളുകൾക്കും ടെസ്റ്റ് കോളുകൾക്കും from_number അക്ഷരാർഥത്തിൽ "web" ആയിരിക്കും |
origin_domain | string | വെബ്/ടെസ്റ്റിന് മാത്രം — വിഡ്ജറ്റ് ഹോസ്റ്റ് ചെയ്ത പേജ് ഒറിജിൻ (മൈക്ക് സെഷനുകൾക്ക് ശൂന്യം) |
start_time, end_time | timestamp | ISO 8601 UTC |
duration_seconds | integer | null | ആരംഭ/അവസാന സമയങ്ങളിൽ നിന്ന് നിർണയിക്കുന്നത് |
status | string | completed അല്ലെങ്കിൽ failed |
end_reason | string | താഴെയുള്ള പട്ടിക കാണുക |
product, voice | string | കോൾ സമയത്ത് പ്രാബല്യത്തിലുള്ള ഏജന്റ് കോൺഫിഗറേഷൻ |
transfer_number | string | null | കോൾ ട്രാൻസ്ഫർ ചെയ്തപ്പോൾ സജ്ജമാക്കുന്നു |
recording_url | string | null | കാലഹരണപ്പെടുന്ന സൈൻ ചെയ്ത URL; ഉടൻ ഡൗൺലോഡ് ചെയ്യുക. റെക്കോർഡിംഗ് ആർട്ടിഫാക്ട് ലഭ്യമല്ലാത്തപ്പോൾ null |
billable_minutes | number | ബിൽ ചെയ്യുന്ന മിനിറ്റുകൾ, ഏറ്റവും അടുത്ത ക്വാർട്ടർ മിനിറ്റിലേക്ക് റൗണ്ട് ചെയ്തത് (15-സെക്കൻഡ് ഇൻക്രിമെന്റുകൾ, കുറഞ്ഞത് 0.25). നേരിട്ട് വോയ്സ്മെയിലിലേക്കുള്ള കോളുകൾ അവരുടെ യഥാർഥ മീറ്റർ ചെയ്ത മിനിറ്റുകൾ ഇവിടെ റിപ്പോർട്ട് ചെയ്യുമെങ്കിലും, പ്ലാൻ നിരക്കിൽ ചാർജ് ഒരു മിനിറ്റായി പരിമിതപ്പെടുത്തിയിരിക്കും. |
billing_total_cents | integer | USD സെന്റുകൾ |
transcripts | array | ഓരോ ടേണിലെയും ട്രാൻസ്ക്രിപ്റ്റ് എൻട്രികൾ; ട്രാൻസ്ക്രിപ്റ്റ് ലഭ്യമല്ലാത്തപ്പോൾ ശൂന്യമായിരിക്കാം |
അവസാനിപ്പിക്കാനുള്ള കാരണങ്ങൾ
| മൂല്യം | അർത്ഥം |
|---|---|
user_hangup | മറുവശത്തുള്ള വ്യക്തി ആദ്യം കോൾ വിച്ഛേദിച്ചു |
ai_hangup | AI മനഃപൂർവം കോൾ അവസാനിപ്പിച്ചു |
ai_transfer | AI കോൾ ട്രാൻസ്ഫർ ചെയ്തു; transfer_number സജ്ജമാക്കിയിരിക്കും |
ai_warm_transfer | AI ഒരു വോം (അറ്റൻഡഡ്) ട്രാൻസ്ഫർ പൂർത്തിയാക്കി |
voicemail_hangup | വോയ്സ്മെയിൽ കണ്ടെത്തി, നിങ്ങളുടെ voicemail_action അനുസരിച്ച് കോൾ അവസാനിപ്പിച്ചു |
max_duration | കോൾ പരമാവധി ദൈർഘ്യ പരിധിയിലെത്തി |
superseded | സെഷൻ പുതിയൊന്നാൽ മാറ്റിസ്ഥാപിക്കപ്പെട്ടു |
unknown | അവസാനിപ്പിക്കാനുള്ള കാരണം നിർണയിക്കാനായില്ല |
ട്രാൻസ്ക്രിപ്റ്റ് ഫോർമാറ്റ്
transcripts-ലെ ഓരോ എൻട്രിയും ഒരു സംഭാഷണ ടേണാണ്. റോളുകൾ
user (വിളിക്കുന്നയാളുടെ സംഭാഷണം), model (ഏജന്റിന്റെ സംഭാഷണവും ടൂൾ കോളുകളും),
tool (ടൂൾ ഫലങ്ങൾ), system (ഭാഷാ മാറ്റങ്ങൾ പോലുള്ള കോൾ
ഇവന്റുകൾ) എന്നിവയാണ്.
[
{
"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"] }
}
}
]
| ഫീൽഡ് | തരം | വിവരണം |
|---|---|---|
role | സ്ട്രിംഗ് | user, model, tool, അല്ലെങ്കിൽ system |
content_type | സ്ട്രിംഗ് | സംസാരത്തിന് text/plain; ടൂൾ കോളുകൾ, ടൂൾ ഫലങ്ങൾ, സിസ്റ്റം ഇവന്റുകൾ എന്നിവയ്ക്ക് application/json |
content | സ്ട്രിംഗ് | ഒബ്ജക്റ്റ് | സംസാര വാചകം അല്ലെങ്കിൽ മുകളിൽ കാണിച്ച ഘടനാപരമായ ഒബ്ജക്റ്റ്. ടൂൾ കോളുകൾ: {"tool_call": name, "arguments": {…}}. ടൂൾ ഫലങ്ങൾ: {"tool_name": name, "response": {…}} |
start_ms, end_ms | ഇന്റിജർ | കോൾ ആരംഭത്തിൽ നിന്നുള്ള ഓഫ്സെറ്റുകൾ, ms. ഓഡിയോ ടൈമിങ് അറിയുമ്പോൾ ഉണ്ടായിരിക്കും |
ttfa_ms | ഇന്റിജർ | അളക്കുമ്പോൾ, ഒരു model ടേണിന്റെ ആദ്യ ഓഡിയോയിലേക്കുള്ള സമയം |
audio_url, audio_urls | സ്ട്രിംഗ് / അറേ | ഓരോ ടേണായും റെക്കോർഡ് ചെയ്യുമ്പോൾ, ആ ടേണിന്റെ ഓഡിയോയ്ക്കുള്ള കാലഹരണപ്പെടുന്ന സൈൻ ചെയ്ത URL-കൾ |
ഇടപെടൽ മാർക്കറുകൾ, ack-prompt-ുകൾ, റോ പൊസിഷനുകൾ എന്നിവയുള്ള പൂർണമായും
ഘടനാപരമായ ടേൺ ചരിത്രത്തിനായി,
GET /v1/calls/{call_id}/history ഉപയോഗിക്കുക.
ലെഗസി പേലോഡ് വ്യത്യാസങ്ങൾ
ലെഗസി സിംഗിൾ-URL വെബ്ഹുക്ക് എൻവലപ്പ്
{"type": "telephony.complete" | "web.complete", "data": {…}} ആണ്; ഇതിൽ
event_id ഇല്ല, കൂടാതെ അതിന്റെ data എൻഡ്പോയിന്റ് പേലോഡിൽ നിന്ന് വ്യത്യസ്തമാണ്:
- ടേൺ അറേ
transcripts-ലല്ല,history-ലാണ് (മുകളിൽ നൽകിയ അതേ ടേൺ സ്കീമ). - ഫീൽഡ് സെറ്റ് റോ എൻഡ്-ഓഫ്-കോൾ റിപ്പോർട്ടാണ്; മുകളിലെ പട്ടികയ്ക്കപ്പുറം അധിക ഇന്റേണൽ ഫീൽഡുകൾ ഉൾപ്പെടാം — അറിയാത്ത ഫീൽഡുകളെ വിവരപരമായി കണക്കാക്കുക.
- വെബ് കോളുകൾ (
direction: "web")from_number/to_numberഒഴിവാക്കുകയുംorigin_domainചേർക്കുകയും ചെയ്യുന്നു. - ബിൽഡർ മൈക്ക് ടെസ്റ്റ് കോളുകൾ ലെഗസി പാതയിൽ
telephony.completeആയി റിപ്പോർട്ട് ചെയ്യപ്പെടുന്നു (എൻഡ്പോയിന്റ് സിസ്റ്റം അവയെweb.complete-ലേക്ക് മാപ്പ് ചെയ്യുന്നു). - ട്രാൻസ്ഫർ ഏകോപനം: ഒരു കോൾ ട്രാൻസ്ഫറിൽ അവസാനിക്കുമ്പോൾ,
ലെഗസി വെബ്ഹുക്ക് സിൻക്രണസായി വിളിക്കപ്പെടുകയും ഹാൻഡ്ഓഫ് ലക്ഷ്യം
തയ്യാറല്ലെന്ന് സൂചിപ്പിക്കാൻ
{"transfer_ready": false}മറുപടി നൽകുകയും ചെയ്യാം. മറ്റേതെങ്കിലും മറുപടി (അല്ലെങ്കിൽ ലെഗസി വെബ്ഹുക്ക് ഇല്ലായ്മ) ട്രാൻസ്ഫർ തുടരാൻ അനുവദിക്കുന്നു. ഇതിനായി എൻഡ്പോയിന്റ് ഡെലിവറികൾ ഒരിക്കലും പരിശോധിക്കില്ല.
ഉദാഹരണ ഹാൻഡ്ലർ
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 });
},
);
സാധാരണ ഉപയോഗ സാഹചര്യങ്ങൾ
ഓരോ കോളിന്റെയും ട്രാൻസ്ക്രിപ്റ്റും റെക്കോർഡിംഗ് URL-ഉം നിങ്ങളുടെ ഉപഭോക്തൃ റെക്കോർഡുകൾക്കൊപ്പം സംഭരിക്കുക.
വിഷയം മോഡലിംഗ്, CSAT സിഗ്നൽ എക്സ്ട്രാക്ഷൻ, അല്ലെങ്കിൽ ട്രാൻസ്ഫർ നിരക്ക് നിരീക്ഷണം എന്നിവയ്ക്കായി ട്രാൻസ്ക്രിപ്റ്റുകൾ ഒരു പൈപ്പ്ലൈനിലേക്ക് സ്ട്രീം ചെയ്യുക.
മാനുഷിക അവലോകനത്തിനായി കോളുകൾ ഒരു QA ടൂളിൽ തുറക്കുക, അല്ലെങ്കിൽ അവയെ നിങ്ങളുടെ സ്വന്തം മൂല്യനിർണയ മോഡലിലൂടെ പ്രവർത്തിപ്പിക്കുക.
ട്രാൻസ്ഫർ / പരാജയം സംഭവിക്കുമ്പോൾ ഒരു മാനുഷിക സഹപ്രവർത്തകനെ ട്രിഗർ ചെയ്യുക.