telephony.complete / web.complete
ஒவ்வொரு அழைப்பும் முடிந்த பிறகு ஒரு நிறைவு நிகழ்வு தூண்டப்படும் — உள்வரும் தொலைபேசி அழைப்பு, வெளிச்செல்லும் தொலைபேசி அழைப்பு, வலை அழைப்பு அல்லது சோதனை அழைப்பு (பில்டர் மைக் அமர்வு). இது தடையற்றது: எந்த 2xx பதிலையும் அனுப்புங்கள்.
நிகழ்வு இரண்டு பாதைகளிலும் வழங்கப்படும்:
- Webhook எண்ட்பாயிண்ட்கள் நிலையான பேலோடுடன்
telephony.complete(தொலைபேசி அழைப்புகள்) அல்லதுweb.complete(வலை அழைப்புகள் மற்றும் பில்டர் மைக் சோதனை அழைப்புகள்) பெறும்; கீழே ஆவணப்படுத்தப்பட்டுள்ளபடி, ஒவ்வொரு வழங்கலுக்கும் ஒருevent_id, 30 s காலவரம்பு மற்றும் 24 h வரை மீண்டும் முயற்சிகள் இருக்கும். - பழைய ஒற்றை-URL webhook சற்று வேறுபட்ட பேலோடுடன் ஒரு ஒத்திசைவு முயற்சியைப் பெறும் (10 s காலவரம்பு, மீண்டும் முயற்சிகள் இல்லை) — பழைய பேலோட் வேறுபாடுகள் என்பதைப் பார்க்கவும்.
கோரிக்கை பேலோட் (எண்ட்பாயிண்ட் வழங்கல்கள்)
{
"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 | string | user, model, tool, அல்லது system |
content_type | string | பேச்சுக்கு text/plain; கருவி அழைப்புகள், கருவி முடிவுகள் மற்றும் சிஸ்டம் நிகழ்வுகளுக்கு application/json |
content | string | object | பேச்சு உரை அல்லது மேலே காட்டப்பட்ட கட்டமைக்கப்பட்ட ஆப்ஜெக்ட். கருவி அழைப்புகள்: {"tool_call": name, "arguments": {…}}. கருவி முடிவுகள்: {"tool_name": name, "response": {…}} |
start_ms, end_ms | integer | அழைப்பு தொடக்கத்திலிருந்து ஆஃப்செட்கள், ms. ஆடியோ நேரம் அறியப்பட்டால் இருக்கும் |
ttfa_ms | integer | அளவிடப்பட்டால், model முறைக்கான முதல்-ஆடியோ-வரை நேரம் |
audio_url, audio_urls | string / array | ஒவ்வொரு முறைக்கும் பதிவு செய்யப்பட்ட ஆடியோவிற்கான காலாவதியாகும் கையொப்பமிடப்பட்ட 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 கருவியில் திறக்கவும் அல்லது அவற்றை உங்கள் சொந்த மதிப்பீட்டு மாடல் மூலம் இயக்கவும்.
பரிமாற்றம் / தோல்வி ஏற்பட்டால் ஒரு மனித குழு உறுப்பினரைத் தூண்டவும்.