ThunderPhone 2.0 ਹੁਣ ਲਾਈਵ ਹੈ।ਸੈਲਫ਼-ਸਰਵਿਸ—2¢/ਮਿੰਟ ਤੋਂਐਲਾਨ ਪੜ੍ਹੋ

Webhooks

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ਇੰਟੀਜਰਇਸ ਕਾਲ ਦੇ ਹਰ ਇਵੈਂਟ ਵਿੱਚ ਸਥਿਰ ਰਹਿੰਦੀ ਹੈ
agent_idਇੰਟੀਜਰ | ਨੱਲਕਾਲ ਸੰਭਾਲਣ ਵਾਲਾ ਏਜੰਟ, ਜਦੋਂ ਕੋਈ ਏਜੰਟ ਅਸਾਈਨ ਕੀਤਾ ਗਿਆ ਹੋਵੇ
agent_nameਸਟਰਿੰਗ | ਨੱਲਕਾਲ ਸੰਭਾਲਣ ਵਾਲੇ ਏਜੰਟ ਦਾ ਨਾਮ, ਜਦੋਂ ਕੋਈ ਏਜੰਟ ਅਸਾਈਨ ਕੀਤਾ ਗਿਆ ਹੋਵੇ
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ਇੰਟੀਜਰ | ਨੱਲਸ਼ੁਰੂਆਤ/ਅੰਤ ਤੋਂ ਪ੍ਰਾਪਤ
statusਸਟਰਿੰਗcompleted ਜਾਂ failed
end_reasonਸਟਰਿੰਗਹੇਠਾਂ ਦਿੱਤੀ ਟੇਬਲ ਵੇਖੋ
product, voiceਸਟਰਿੰਗਕਾਲ ਦੇ ਸਮੇਂ ਲਾਗੂ ਏਜੰਟ ਕਨਫਿਗ
transfer_numberਸਟਰਿੰਗ | ਨੱਲਕਾਲ ਟ੍ਰਾਂਸਫਰ ਹੋਣ 'ਤੇ ਸੈੱਟ ਹੁੰਦਾ ਹੈ
recording_urlਸਟਰਿੰਗ | ਨੱਲਮਿਆਦ ਸਮਾਪਤ ਹੋਣ ਵਾਲਾ ਸਾਈਨ ਕੀਤਾ 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, ਜਦੋਂ ਆਡੀਓ ਹਰ ਵਾਰੀ ਅਨੁਸਾਰ ਰਿਕਾਰਡ ਕੀਤੀ ਗਈ ਹੋਵੇ

ਪੂਰੀ ਤਰ੍ਹਾਂ ਸਟਰਕਚਰਡ ਵਾਰੀ ਇਤਿਹਾਸ ਲਈ (ਰੁਕਾਵਟ ਮਾਰਕਰਾਂ, ਐਕ-ਪ੍ਰੌਮਪਟਾਂ ਅਤੇ ਰਾਅ ਪੁਜ਼ੀਸ਼ਨਾਂ ਸਮੇਤ), ਇਹ ਵਰਤੋ 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 ਜੋੜਿਆ ਜਾਂਦਾ ਹੈ।
  • Builder ਮਾਈਕ ਟੈਸਟ ਕਾਲਾਂ ਪੁਰਾਣੇ ਪਾਥ 'ਤੇ 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 ਟੂਲ ਵਿੱਚ ਖੋਲ੍ਹੋ ਜਾਂ ਉਨ੍ਹਾਂ ਨੂੰ ਆਪਣੇ ਮੁਲਾਂਕਣ ਮਾਡਲ ਰਾਹੀਂ ਚਲਾਓ।

ਸੂਚਨਾਵਾਂ

ਟ੍ਰਾਂਸਫਰ ਜਾਂ ਅਸਫਲਤਾ ਹੋਣ 'ਤੇ ਮਨੁੱਖੀ ਟੀਮ ਮੈਂਬਰ ਨੂੰ ਸੂਚਿਤ ਕਰੋ।


ਸੰਬੰਧਿਤ