Open in
telephony.complete / web.complete
കോൾ അവസാനിക്കുമ്പോൾ ട്രാൻസ്ക്രിപ്റ്റ്, റെക്കോർഡിംഗ് URL, മെട്രിക്കുകൾ എന്നിവയുമായി കൈമാറുന്ന നോൺ-ബ്ലോക്കിംഗ് വെബ്ഹുക്ക്.
ഓരോ കോൾ അവസാനിച്ചതിന് ശേഷവും ഒരു completion ഇവന്റ് പ്രവർത്തിക്കും — ഇൻബൗണ്ട് ടെലിഫോണി, ഔട്ട്ബൗണ്ട് ടെലിഫോണി, വെബ് കോൾ, അല്ലെങ്കിൽ ടെസ്റ്റ് കോൾ (builder മൈക്ക് സെഷൻ). ഇത് തടസ്സമില്ലാത്തതാണ്: ഏതെങ്കിലും 2xx ഉപയോഗിച്ച് പ്രതികരിക്കുക.
ഇവന്റ് രണ്ട് പാതകളിലും കൈമാറുന്നു:
- Webhook എൻഡ്പോയിന്റുകൾ-ക്ക്
telephony.complete(ഫോൺ കോളുകൾ) അല്ലെങ്കിൽweb.complete(വെബ് കോളുകളും builder മൈക്ക് ടെസ്റ്റ് കോളുകളും) താഴെ രേഖപ്പെടുത്തിയ സ്ഥിരതയുള്ള payload, ഓരോ ഡെലിവറിക്കുംevent_id, 30 s ടൈംഔട്ട്, കൂടാതെ 24 h വരെ റീട്രൈകൾ എന്നിവയോടെ ലഭിക്കും. - ലെഗസി ഒറ്റ-URL webhook-ക്ക് അല്പം വ്യത്യസ്തമായ payload ഉപയോഗിച്ച് ഒരു synchronous ശ്രമം ലഭിക്കും (10 s ടൈംഔട്ട്, റീട്രൈകളില്ല) — കാണുക ലെഗസി payload വ്യത്യാസങ്ങൾ.
റിക്വസ്റ്റ് payload (എൻഡ്പോയിന്റ് ഡെലിവറികൾ)
{
"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 | ഈ കോളിനായുള്ള എല്ലാ ഇവന്റുകളിലും സ്ഥിരതയുള്ളത് |
agent_id | integer | null | ഏജന്റിനെ നിയോഗിച്ചിരുന്നെങ്കിൽ, കോൾ കൈകാര്യം ചെയ്ത ഏജന്റ് |
agent_name | string | null | ഏജന്റിനെ നിയോഗിച്ചിരുന്നെങ്കിൽ, കോൾ കൈകാര്യം ചെയ്ത ഏജന്റ് |
direction | string | inbound, outbound, web, test. പഴയ payload-കളിൽ ലെഗസി mic അല്ലെങ്കിൽ widget മൂല്യങ്ങൾ ഉണ്ടായേക്കാം |
from_number, to_number | string | E.164. വെബ് കോളുകൾക്കും ടെസ്റ്റ് കോളുകൾക്കും from_number അക്ഷരാർഥത്തിലുള്ള "web" ആണ് |
origin_domain | string | വെബ്/ടെസ്റ്റിന് മാത്രം — widget ഹോസ്റ്റ് ചെയ്ത പേജ് ഉത്ഭവം (മൈക്ക് സെഷനുകൾക്ക് ശൂന്യം) |
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 | കാലഹരണപ്പെടുന്ന signed 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-കൾ |
തടസ്സ മാർക്കറുകൾ, അക്-പ്രോംപ്റ്റുകൾ, റോ സ്ഥാനങ്ങൾ എന്നിവയുള്ള പൂർണ ഘടനാപരമായ ടേൺ ചരിത്രത്തിനായി,
GET /v1/calls/{call_id}/history ഉപയോഗിക്കുക.
ലെഗസി പേലോഡ് വ്യത്യാസങ്ങൾ
ലെഗസി സിംഗിൾ-URL വെബ്ഹുക്ക് എൻവലപ്പ്
{"type": "telephony.complete" | "web.complete", "data": {…}} ആണ്, ഇതിൽ
event_id ഇല്ല, കൂടാതെ അതിന്റെ data എൻഡ്പോയിന്റ് പേലോഡിൽനിന്ന് വ്യത്യസ്തമാണ്:
ലെഗസി കംപ്ലീഷൻ പേലോഡിൽ agent_id, agent_name എന്നിവയും ഉൾപ്പെടുന്നു.
- ടേൺ അറേ
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 ടൂളിൽ തുറക്കുക, അല്ലെങ്കിൽ അവയെ നിങ്ങളുടെ സ്വന്തം മൂല്യനിർണയ മോഡലിലൂടെ പ്രവർത്തിപ്പിക്കുക.
ട്രാൻസ്ഫർ / പരാജയത്തിൽ ഒരു മാനുഷിക സഹപ്രവർത്തകനെ ട്രിഗർ ചെയ്യുക.