ThunderPhone 2.0 ഇപ്പോൾ ലൈവാണ്.സ്വയം തുടങ്ങാം — 2¢/മിനിറ്റ് മുതൽ.പ്രഖ്യാപനം വായിക്കുക

Webhooks

telephony.complete / web.complete

കോൾ അവസാനിക്കുമ്പോൾ ട്രാൻസ്ക്രിപ്റ്റ്, റെക്കോർഡിംഗ് URL, മെട്രിക്കുകൾ എന്നിവയുമായി കൈമാറുന്ന നോൺ-ബ്ലോക്കിംഗ് വെബ്ഹുക്ക്.

ഓരോ കോൾ അവസാനിച്ചതിന് ശേഷവും ഒരു completion ഇവന്റ് പ്രവർത്തിക്കും — ഇൻബൗണ്ട് ടെലിഫോണി, ഔട്ട്ബൗണ്ട് ടെലിഫോണി, വെബ് കോൾ, അല്ലെങ്കിൽ ടെസ്റ്റ് കോൾ (builder മൈക്ക് സെഷൻ). ഇത് തടസ്സമില്ലാത്തതാണ്: ഏതെങ്കിലും 2xx ഉപയോഗിച്ച് പ്രതികരിക്കുക.

ഇവന്റ് രണ്ട് പാതകളിലും കൈമാറുന്നു:

റിക്വസ്റ്റ് 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_idintegerഈ കോളിനായുള്ള എല്ലാ ഇവന്റുകളിലും സ്ഥിരതയുള്ളത്
agent_idinteger | nullഏജന്റിനെ നിയോഗിച്ചിരുന്നെങ്കിൽ, കോൾ കൈകാര്യം ചെയ്ത ഏജന്റ്
agent_namestring | nullഏജന്റിനെ നിയോഗിച്ചിരുന്നെങ്കിൽ, കോൾ കൈകാര്യം ചെയ്ത ഏജന്റ്
directionstringinbound, outbound, web, test. പഴയ payload-കളിൽ ലെഗസി mic അല്ലെങ്കിൽ widget മൂല്യങ്ങൾ ഉണ്ടായേക്കാം
from_number, to_numberstringE.164. വെബ് കോളുകൾക്കും ടെസ്റ്റ് കോളുകൾക്കും from_number അക്ഷരാർഥത്തിലുള്ള "web" ആണ്
origin_domainstringവെബ്/ടെസ്റ്റിന് മാത്രം — widget ഹോസ്റ്റ് ചെയ്ത പേജ് ഉത്ഭവം (മൈക്ക് സെഷനുകൾക്ക് ശൂന്യം)
start_time, end_timetimestampISO 8601 UTC
duration_secondsinteger | nullആരംഭ/അവസാന സമയത്തിൽനിന്ന് നിർണയിച്ചത്
statusstringcompleted അല്ലെങ്കിൽ failed
end_reasonstringതാഴെയുള്ള പട്ടിക കാണുക
product, voicestringകോൾ സമയത്ത് പ്രാബല്യത്തിലിരുന്ന ഏജന്റ് കോൺഫിഗറേഷൻ
transfer_numberstring | nullകോൾ ട്രാൻസ്ഫർ ചെയ്തപ്പോൾ സജ്ജമാക്കുന്നു
recording_urlstring | nullകാലഹരണപ്പെടുന്ന signed URL; ഉടൻ ഡൗൺലോഡ് ചെയ്യുക. റെക്കോർഡിംഗ് ആർട്ടിഫാക്ട് ലഭ്യമല്ലാത്തപ്പോൾ null
billable_minutesnumberബിൽ ചെയ്ത മിനിറ്റുകൾ, ഏറ്റവും അടുത്ത കാൽ മിനിറ്റിലേക്ക് റൗണ്ട് ചെയ്തത് (15-സെക്കൻഡ് വർധനകൾ, കുറഞ്ഞത് 0.25). നേരിട്ട് വോയ്‌സ്‌മെയിലിലേക്കുള്ള കോളുകൾ ഇവയുടെ യഥാർഥ മീറ്റർ ചെയ്ത മിനിറ്റുകൾ ഇവിടെ റിപ്പോർട്ട് ചെയ്യും, എന്നാൽ പ്ലാൻ നിരക്കിലുള്ള ചാർജ് ഒരു മിനിറ്റായി പരിമിതപ്പെടുത്തും.
billing_total_centsintegerUSD സെന്റുകൾ
transcriptsarrayഓരോ ടേണിലെയും ട്രാൻസ്ക്രിപ്റ്റ് എൻട്രികൾ; ട്രാൻസ്ക്രിപ്റ്റ് ലഭ്യമല്ലാത്തപ്പോൾ ശൂന്യമായിരിക്കാം

അവസാനിപ്പിക്കൽ കാരണങ്ങൾ

മൂല്യംഅർഥം
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സ്ട്രിംഗ് / അറേഓരോ ടേണായും റെക്കോർഡ് ചെയ്യുമ്പോൾ, ആ ടേണിന്റെ ഓഡിയോയ്ക്കുള്ള കാലഹരണപ്പെടുന്ന സൈൻ ചെയ്ത 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} മറുപടി നൽകുകയും ചെയ്യാം. മറ്റേതെങ്കിലും മറുപടി (അല്ലെങ്കിൽ ലെഗസി വെബ്ഹുക്ക് ഇല്ലായ്മ) ട്രാൻസ്ഫർ തുടരാൻ അനുവദിക്കും. ഇതിനായി എൻഡ്പോയിന്റ് ഡെലിവറികൾ ഒരിക്കലും പരിശോധിക്കില്ല.

ഉദാഹരണ ഹാൻഡ്‌ലർ

Python (FastAPI)
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}
Node.js (Express)
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 ടൂളിൽ തുറക്കുക, അല്ലെങ്കിൽ അവയെ നിങ്ങളുടെ സ്വന്തം മൂല്യനിർണയ മോഡലിലൂടെ പ്രവർത്തിപ്പിക്കുക.

അറിയിപ്പുകൾ

ട്രാൻസ്ഫർ / പരാജയത്തിൽ ഒരു മാനുഷിക സഹപ്രവർത്തകനെ ട്രിഗർ ചെയ്യുക.


ബന്ധപ്പെട്ടവ