telephony.complete / web.complete

દરેક કૉલ પૂર્ણ થયા પછી એક કંપ્લીશન ઇવેન્ટ ફાયર થાય છે — ઇનબાઉન્ડ ટેલિફોની, આઉટબાઉન્ડ ટેલિફોની, વેબ કૉલ અથવા ટેસ્ટ કૉલ (બિલ્ડર માઇક સેશન). તે નોન-બ્લોકિંગ છે: કોઈપણ 2xx સાથે પ્રતિસાદ આપો.

ઇવેન્ટ બંને પાથ પર ડિલિવર થાય છે:

રિક્વેસ્ટ પેલોડ (એન્ડપૉઇન્ટ ડિલિવરીઝ)

{
  "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ઇન્ટીજરઆ કૉલ માટેની દરેક ઇવેન્ટમાં સ્થિર રહે છે
directionસ્ટ્રિંગinbound, outbound, web, test. ઐતિહાસિક પેલોડમાં જૂના mic અથવા widget મૂલ્યો હોઈ શકે છે
from_number, to_numberસ્ટ્રિંગE.164. વેબ કૉલ્સ અને ટેસ્ટ કૉલ્સ માટે from_number શાબ્દિક "web" હોય છે
origin_domainસ્ટ્રિંગફક્ત વેબ/ટેસ્ટ — વિજેટ હોસ્ટ કરનાર પેજ ઓરિજિન (માઇક સેશન માટે ખાલી)
start_time, end_timeટાઇમસ્ટેમ્પISO 8601 UTC
duration_secondsઇન્ટીજર | nullશરૂઆત/અંત પરથી મેળવેલ
statusસ્ટ્રિંગcompleted અથવા failed
end_reasonસ્ટ્રિંગનીચેનું ટેબલ જુઓ
product, voiceસ્ટ્રિંગકૉલ સમયે સક્રિય એજન્ટ કન્ફિગ
transfer_numberસ્ટ્રિંગ | nullકૉલ ટ્રાન્સફર થયો હોય ત્યારે સેટ થાય છે
recording_urlસ્ટ્રિંગ | nullસમયસમાપ્તિ ધરાવતો સાઇન્ડ URL; સમયસર ડાઉનલોડ કરો. કોઈ રેકોર્ડિંગ આર્ટિફેક્ટ ઉપલબ્ધ ન હોય ત્યારે null
billable_minutesનંબરબિલ કરેલા મિનિટ, સૌથી નજીકના ચોથા મિનિટ સુધી રાઉન્ડ કરેલા (15-સેકન્ડના વધારા, ન્યૂનતમ 0.25). સીધા વૉઇસમેઇલ પર જતા કૉલ્સ પણ અહીં તેમના વાસ્તવિક મીટર થયેલા મિનિટ દર્શાવે છે, પરંતુ પ્લાન દરે ચાર્જ એક મિનિટ સુધી મર્યાદિત હોય છે.
billing_total_centsઇન્ટીજરUSD સેન્ટ્સ
transcriptsએરેદરેક ટર્ન માટેની ટ્રાન્સક્રિપ્ટ એન્ટ્રીઓ; ટ્રાન્સક્રિપ્ટ ઉપલબ્ધ ન હોય ત્યારે ખાલી હોઈ શકે છે

અંતના કારણો

મૂલ્યઅર્થ
user_hangupબીજી બાજુની વ્યક્તિએ પહેલાં કૉલ કાપ્યો
ai_hangupAI એ ઇરાદાપૂર્વક કૉલ સમાપ્ત કર્યો
ai_transferAI એ કૉલ ટ્રાન્સફર કર્યો; transfer_number સેટ થાય છે
ai_warm_transferAI એ વૉર્મ (એટેન્ડેડ) ટ્રાન્સફર પૂર્ણ કર્યો
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સ્ટ્રિંગ / એરેદરેક વારાના ઑડિયો માટે સમાપ્તિ ધરાવતા સહીકૃત URLs, જ્યારે પ્રતિ-વારો રેકોર્ડ કરવામાં આવ્યો હોય

વિરામચિહ્નો, સ્વીકૃતિ-prompt અને કાચી સ્થિતિઓ સહિતના સંપૂર્ણ સંરચિત વારા ઇતિહાસ માટે, GET /v1/calls/{call_id}/historyનો ઉપયોગ કરો.

જૂના payloadમાં તફાવતો

જૂનું સિંગલ-URL વેબહૂક એન્વલપ {"type": "telephony.complete" | "web.complete", "data": {…}} છે, જેમાં event_id હોતું નથી, અને તેનું data એન્ડપોઇન્ટ payloadથી અલગ છે:


ઉદાહરણ હેન્ડલર

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 });
  },
);

સામાન્ય ઉપયોગના કિસ્સાઓ

CRM એકીકરણ

દરેક કૉલનો ટ્રાન્સક્રિપ્ટ અને રેકોર્ડિંગ URL તમારા ગ્રાહક રેકોર્ડ્સ સાથે સંગ્રહિત કરો.

એનલિટિક્સ

વિષય મોડેલિંગ, CSAT સિગ્નલ નિષ્કર્ષણ અથવા ટ્રાન્સફર-દર મોનિટરિંગ માટે ટ્રાન્સક્રિપ્ટ્સને પાઇપલાઇનમાં સ્ટ્રીમ કરો.

ગુણવત્તા સમીક્ષા

માનવ સમીક્ષા માટે કૉલ્સને QA ટૂલમાં ખોલો અથવા તેમને તમારા પોતાના મૂલ્યાંકન મોડેલ દ્વારા ચલાવો.

સૂચનાઓ

ટ્રાન્સફર / નિષ્ફળતા પર માનવ ટીમસાથીને ટ્રિગર કરો.


સંબંધિત