---
title: "telephony.complete / web.complete"
description: "Nebloķējošs tīmekļa aizķeres paziņojums, kas tiek nosūtīts, kad zvans beidzas, ar transkriptu, ieraksta URL un rādītājiem."
---

Pabeigšanas notikums tiek aktivizēts pēc katra zvana beigām — ienākošās telefonijas,
izejošās telefonijas, tīmekļa zvana vai testa zvana (veidotāja mikrofona sesijas). Tas ir
**nebloķējošs**: atbildiet ar jebkuru 2xx.

Notikums tiek nosūtīts pa abiem ceļiem:

* **[Tīmekļa aizķeru galapunkti](/lv/webhooks/endpoints)** saņem
  `telephony.complete` (tālruņa zvani) vai `web.complete` (tīmekļa zvani un
  veidotāja mikrofona testa zvani) ar tālāk dokumentēto stabilo datu slodzi,
  katrai piegādei piešķirtu `event_id`, 30 s noildzi un
  [atkārtotiem mēģinājumiem līdz 24 h](/lv/webhooks/overview).
* **[Mantotā vienas URL tīmekļa aizķere](/api-reference/organizations#legacy-single-url-webhook)**
  saņem vienu sinhronu mēģinājumu (10 s noildze, bez atkārtotiem mēģinājumiem) ar
  nedaudz atšķirīgu datu slodzi — skatiet
  [Mantotās datu slodzes atšķirības](#legacy-payload-differences).

## Pieprasījuma slodze (galapunkta piegādes)

```json
{
  "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",
    "extracted_data": {
      "status": "completed",
      "fields": {
        "customer_name": "Alex Morgan",
        "appointment_date": "2026-04-23"
      },
      "evidence": {
        "customer_name": {
          "quote": "My name is Alex Morgan",
          "speaker_role": "caller",
          "turn_index": 4
        },
        "appointment_date": {
          "quote": "April 23 works for me",
          "speaker_role": "caller",
          "turn_index": 7
        }
      },
      "verification": "verified",
      "field_reasons": {},
      "schema_version": "92850758e231a3c95a..."
    },
    "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,
    "unresolved_variables": ["campaign_owner"],
    "variables": {"campaign_name": "Spring renewals"},
    "voice": "john"
  },
  "event_id": "6a7b8c9d-0e1f-4a2b-8c3d-4e5f6a7b8c9d",
  "type": "telephony.complete"
}
```

| Lauks | Tips | Apraksts |
|-------|------|-------------|
| `call_id` | integer | Nemainīgs visos šī zvana notikumos |
| `agent_id` | integer \| null | Balss aģents, kas apstrādāja zvanu, ja tāds bija piešķirts |
| `agent_name` | string \| null | Balss aģents, kas apstrādāja zvanu, ja tāds bija piešķirts |
| `direction` | string | `inbound`, `outbound`, `web`, `test`. Vēsturiskajās slodzēs var būt mantotās vērtības `mic` vai `widget` |
| `from_number`, `to_number` | string | E.164. Tīmekļa un testa zvaniem `from_number` burtiski ir `"web"` |
| `origin_domain` | string | **Tikai tīmeklim/testam** — lapas izcelsme, kurā tika mitināts logrīks (tukša mikrofona sesijām) |
| `start_time`, `end_time` | timestamp | ISO 8601 UTC |
| `duration_seconds` | integer \| null | Atvasināts no sākuma/beigu laika |
| `status` | string | `completed` vai `failed` |
| `end_reason` | string | Skatiet tālāk esošo tabulu |
| `product`, `voice` | string | Zvana laikā spēkā esošā balss aģenta konfigurācija |
| `variables` | object | Ievades mainīgie, kuru momentuzņēmums tika izveidots zvana sākumā |
| `unresolved_variables` | array | Mainīgo nosaukumi, uz kuriem atsaucas zvana konfigurācija, bet kuri netika norādīti zvana sākumā |
| `transfer_number` | string \| null | Iestatīts, kad zvans tika pārsūtīts |
| `recording_url` | string \| null | Parakstīts URL ar derīguma termiņu; lejupielādējiet nekavējoties. `null`, ja ieraksta artefakts nav pieejams |
| `billable_minutes` | number | Rēķinā iekļautās minūtes, noapaļotas līdz tuvākajai ceturtdaļminūtei (15 sekunžu intervāli, minimums 0,25). Zvani, kas uzreiz nonāk balss pastā, arī šeit norāda faktiskās uzskaitītās minūtes, taču maksa ir ierobežota līdz vienai minūtei pēc plāna tarifa. |
| `billing_total_cents` | integer | ASV dolāru centi |
| `transcripts` | array | Transkripcijas ieraksti katram gājienam; var būt tukšs, ja transkripcija nav pieejama |
| `extracted_data` | object \| null | Strukturēts ekstrakcijas rezultāts ar `status`, `fields`, `evidence`, `verification`, `field_reasons` un `schema_version`. Katram laukam, kas nav null, ir precīzs strukturāli pārbaudīts citāts (ne vairāk kā 1000 rakstzīmes), kā arī runātāja loma un gājiena indekss; garāki modeļa atgrieztie citāti tiek noraidīti, nevis saīsināti. Pierādījums ir `null`, ja lauks ir `null`. `verified` nozīmē, ka katrs kandidāts saņēma tieši vienu derīgu neatkarīgu vērtējumu. `unavailable` aptver arī nepareizu vai daļēju verificētāja izvadi; derīgi daļēji vērtējumi joprojām tiek piemēroti, bet kandidāti bez viena derīga vērtējuma tiek iestatīti uz nulli. `status` ir `completed`, `failed`, `exhausted`, `skipped` vai `skipped_recording_disabled`; `null`, ja balss aģentam nebija ekstrakcijas lauku |

### Beigu iemesli

| Vērtība | Nozīme |
|-------|---------|
| `user_hangup` | Attālā puse pirmā nolika klausuli |
| `ai_hangup` | MI apzināti beidza zvanu |
| `ai_transfer` | MI pārsūtīja zvanu; ir iestatīts `transfer_number` |
| `ai_warm_transfer` | MI pabeidza silto (ar apstiprinājumu) pārsūtīšanu |
| `voicemail_hangup` | Tika noteikts balss pasts, un zvans tika pabeigts atbilstoši jūsu `voicemail_action` |
| `max_duration` | Zvans sasniedza maksimālā ilguma ierobežojumu |
| `superseded` | Sesija tika aizstāta ar jaunāku sesiju |
| `unknown` | Beigu iemeslu nevarēja noteikt |

## Transkripta formāts

Katrs ieraksts `transcripts` masīvā ir viena sarunas kārta. Lomas ir
`user` (zvanītāja runa), `model` (balss aģenta runa **un** rīku izsaukumi),
`tool` (rīku rezultāti) un `system` (zvana notikumi, piemēram, valodas
maiņa).

```json
[
  {
    "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"] }
    }
  }
]
```

| Lauks | Tips | Apraksts |
|-------|------|-------------|
| `role` | virkne | `user`, `model`, `tool` vai `system` |
| `content_type` | virkne | `text/plain` runai; `application/json` rīku izsaukumiem, rīku rezultātiem un sistēmas notikumiem |
| `content` | virkne \| objekts | Runas teksts vai iepriekš parādītais strukturētais objekts. Rīku izsaukumi: `{"tool_call": name, "arguments": {…}}`. Rīku rezultāti: `{"tool_name": name, "response": {…}}` |
| `start_ms`, `end_ms` | vesels skaitlis | Nobīdes no zvana sākuma milisekundēs. Tiek iekļautas, ja ir zināms audio laiks |
| `ttfa_ms` | vesels skaitlis | Laiks līdz pirmajam audio `model` kārtai, ja tas ir izmērīts |
| `audio_url`, `audio_urls` | virkne / masīvs | Parakstīti URL ar derīguma termiņu kārtas audio ierakstam, ja audio tiek ierakstīts katrai kārtai |

Pilnībā strukturētai kārtu vēsturei (ar pārtraukumu marķieriem,
apstiprinājuma uzvednēm un neapstrādātām pozīcijām) izmantojiet
[`GET /v1/calls/{call_id}/history`](/api-reference/calls#get-history).

## Mantotās slodzes atšķirības

Mantotās viena URL tīmekļa āķa aploksne ir
`{"type": "telephony.complete" | "web.complete", "data": {…}}` bez
**`event_id`**, un tās `data` atšķiras no galapunkta slodzes:

Mantotā pabeigšanas slodze ietver arī `agent_id` un `agent_name`.

* Kārtu masīvs atrodas sadaļā **`history`**, nevis `transcripts` (tāda pati
  kārtu shēma kā iepriekš).
* Lauku kopa ir neapstrādāts zvana beigu pārskats, un tajā var būt
  papildu iekšējie lauki, kas nav norādīti iepriekšējā tabulā — nezināmus
  laukus uzskatiet par informatīviem.
* Tīmekļa zvani (`direction: "web"`) **neiekļauj** `from_number` / `to_number`
  un pievieno `origin_domain`.
* Veidotāja mikrofona pārbaudes zvani mantotajā ceļā tiek ziņoti kā
  `telephony.complete` (galapunkta sistēma tos kartē uz `web.complete`).
* **Pārsūtīšanas koordinēšana:** ja zvans beidzas ar pārsūtīšanu, mantotais
  tīmekļa āķis tiek izsaukts sinhroni un var atbildēt ar
  `{"transfer_ready": false}`, lai norādītu, ka pārsūtīšanas mērķis nav
  gatavs. Jebkura cita atbilde (vai mantotā tīmekļa āķa neesamība) ļauj
  pārsūtīšanai turpināties. Galapunktu piegādes šim nolūkam nekad netiek
  izmantotas.

---

## Piemēra apstrādātājs

<CodeGroup>
```python 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}
```

```javascript 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 });
  },
);
```
</CodeGroup>

---

## Biežākie lietošanas gadījumi

<CardGroup cols={2}>
  <Card title="CRM integrācija" icon="database">
    Saglabājiet katra zvana transkriptu un ieraksta URL kopā ar klientu
    ierakstiem.
  </Card>
  <Card title="Analītika" icon="chart-line">
    Straumējiet transkriptus uz konveijeru tēmu modelēšanai, CSAT signālu
    iegūšanai vai pārsūtīšanas rādītāja uzraudzībai.
  </Card>
  <Card title="Kvalitātes pārbaude" icon="clipboard-check">
    Atveriet zvanus kvalitātes nodrošināšanas rīkā cilvēka veiktai pārbaudei vai palaidiet tos
    savā novērtēšanas modelī.
  </Card>
  <Card title="Paziņojumi" icon="bell">
    Pārsūtīšanas vai kļūmes gadījumā aktivizējiet cilvēku no komandas.
  </Card>
</CardGroup>

---

## Saistītā informācija

<CardGroup cols={2}>
  <Card title="telephony.incoming / web.incoming" icon="phone" href="/lv/webhooks/call-incoming">
    Bloķējošais ekvivalents, kas darbojas zvana sākumā.
  </Card>
  <Card title="Notikumu katalogs" icon="list" href="/lv/webhooks/events">
    Citi notikumu veidi, kuriem varat abonēt.
  </Card>
  <Card title="Zvanu vēstures API" icon="phone" href="/api-reference/calls">
    Tie paši dati, kas pieejami, izmantojot REST, papildināšanai vai atkārtotai atskaņošanai.
  </Card>
</CardGroup>
