---
title: "telephony.incoming / web.incoming"
description: "Блокиращ webhook, който конфигурира входящо обаждане в реално време."
---

Когато входящо телефонно обаждане достигне номер **без назначен
агент** или сесия на уеб уиджет започне с публикуем ключ в
`mode="webhook"`, ThunderPhone изпраща **блокираща**
заявка `telephony.incoming` / `web.incoming` към вашия
[стар URL адрес за webhook](/api-reference/organizations#legacy-single-url-webhook)
и изчаква до **10 секунди** за отговор с конфигурация. Използвайте този
обмен, за да избирате динамично подкана, глас и инструменти за всяко обаждане —
вижте [ръководството за динамична конфигурация на обаждания](/bg/guides/dynamic-call-config)
за цялостния модел.

<Note>
  Абонираните [крайни точки за webhook](/bg/webhooks/endpoints) също получават
  `telephony.incoming` / `web.incoming` — за **всяко** входящо обаждане
  и уеб сесия, независимо дали е конфигуриран агент — но тези доставки са
  известия тип „изпрати и забрави“ с `event_id` и никога не са блокиращи.
  Само старият webhook с един URL адрес пренася обмена на конфигурация
  на тази страница. Форматите на известията от крайните точки са в
  [каталога на събитията](/bg/webhooks/events).
</Note>

Блокиращият обмен няма резервен вариант: ако вашият обработчик върне
статус, различен от 2xx, изтече времето му или върне конфигурация, която не премине
валидация, обаждането се отхвърля (телефонното обаждане не се свързва; заявката
за сесия на уиджета е неуспешна с `502`/`422`). Отговорете бързо — обаждащият се
чува сигнал свободно, докато вземате решение.

<Warning>
  **Обажданията, конфигурирани чрез webhook, не включват съобщение за
  съгласие от ThunderPhone.** Обажданията, конфигурирани чрез този обмен,
  заобикалят съобщението в началото на обаждането на ниво агент и изрично са
  изключени от рамката на ThunderPhone за съобщения за съгласие (Условия за ползване,
  раздел „Записване и съгласие“). Вашата организация носи пълна
  отговорност за всяко известие и съгласие за записване, наблюдение,
  участие на AI и идентифициране на обаждащия се, изисквани при тези обаждания —
  обажданията все пак могат да бъдат записвани, транскрибирани, анализирани и
  обслужвани от AI. Вградете необходимите уведомления в собствения си поток
  на обажданията, преди да активирате този път.
</Warning>

## Полезен товар на заявката

За телефонни обаждания (`telephony.incoming`):

```json
{
  "type": "telephony.incoming",
  "data": {
    "call_id":     987654321,
    "from_number": "+14155550199",
    "to_number":   "+15551234567"
  }
}
```

| Поле | Тип | Описание |
|-------|------|-------------|
| `call_id` | integer | Идентификатор на обаждането — постоянен във всички събития за това обаждане |
| `from_number` | string | Номер на обаждащия се във формат E.164 |
| `to_number` | string | Дестинация във формат E.164 (един от вашите номера на ThunderPhone) |

За сесии на уеб уиджет (`web.incoming`) `data` идентифицира
страницата, в която е вграден уиджетът, вместо телефонни номера:

```json
{
  "type": "web.incoming",
  "data": {
    "call_id": 987654322,
    "origin_domain": "https://example.com",
    "publishable_key_prefix": "pk_live_a1b2"
  }
}
```

| Поле | Тип | Описание |
|-------|------|-------------|
| `call_id` | integer | Идентификатор на обаждането |
| `origin_domain` | string | Произходът на страницата, която хоства уиджета |
| `publishable_key_prefix` | string | Първите символи на публикуемия ключ, който е отворил сесията |
| `language`, `primary_language` | string | Присъства, когато сесията на уиджета е поискала замяна на езика |
| `voice` | string | Присъства, когато сесията на уиджета е поискала замяна на гласа |
| `website_context` | string | Присъства, когато уиджетът е подал контекст на страницата за конкретната сесия |

<Note>
  Уиджетите в режим webhook доставят тази заявка до собствения
  `webhook_url` на публикуемия ключ, когато е зададен такъв, като в противен случай
  използват URL адреса за webhook на ниво организация. И в двата случая заявката е подписана
  с `secret` на webhook за организацията.
</Note>

---

## Схема на отговора

Върнете JSON обект, описващ конфигурацията на агента за това обаждане.
`prompt` и `voice` са задължителни; всичко останало не е задължително.

```json
{
  "prompt":  "You are a helpful booking assistant for Acme Restaurant.",
  "voice":   "john",
  "product": "spark",
  "background_track": null,
  "tools":   []
}
```

| Поле | Тип | Задължително | Описание |
|-------|------|----------|-------------|
| `prompt` | низ | да | Системна подкана, управляваща агента |
| `voice` | низ | да | Идентификатор на глас от [`GET /v1/voices`](/api-reference/agents#voices), напр. `john`. `voice_name` се приема като псевдоним. Непознатите гласове не преминават валидацията и отхвърлят обаждането |
| `product` | низ | не | По подразбиране е `spark`. Разрешени: `spark`, `bolt`, `storm-base`, `storm-base-with-ack`, `storm-extra`, `storm-extra-with-ack` |
| `thinking_level` | низ | не | `minimal`, `base` (по подразбиране) или `extra`. Заменя се за продуктите Storm: `storm-extra*` налага `extra`, а другите `storm-*` налагат `base` |
| `audio_context_mode` | низ | не | `full` (по подразбиране) или `reduced` |
| `watchdog_enabled` | булево | не | Активирайте наблюдение за това обаждане. По подразбиране е `false` |
| `additional_audio_context` | булево \| null | не | Включете последните няколко реплики от аудиото на обаждащия се вместо само най-скорошната реплика, което подобрява корекциите и събирането на данни с много букви/цифри с малко допълнително забавяне/разход. По подразбиране е включено за входящи сесии и изключено за изходящи телефонни обаждания; `null` запазва стойността по подразбиране |
| `storm_feedback_mode` | низ | не | `none`, `acknowledgement` (по подразбиране) или `tick` |
| `language` | низ | не | Съкратен запис за `primary_language` |
| `primary_language` | низ | не | Езиков код, нормализиран (по подразбиране `en`). Неразпознаваемите кодове отхвърлят обаждането |
| `has_additional_languages` | булево | не | По подразбиране е `false` |
| `additional_languages` | масив от низове | не | Допълнителни езици, към които агентът може да превключва |
| `native_voice_switching` | булево | не | По подразбиране е `false`. Когато обаждането премине към друг език, сменете с глас, чийто роден език е този език (съобразен по пол), вместо да запазите конфигурирания глас |
| `background_track` | низ \| null | не | Идентификатор на фоново аудио или `null` |
| `acknowledgement_prompt_mode` | низ | не | `auto` (по подразбиране) или `manual` (продукти Storm с потвърждение) |
| `acknowledgement_prompt` | низ | не | Използва се, когато `acknowledgement_prompt_mode="manual"` |
| `silence_interval_seconds` | цяло число \| null | не | 5–120. Секунди мълчание на обаждащия се преди проверка |
| `silence_max_checkins` | цяло число \| null | не | 1–10 |
| `silence_checkins_enabled` | булево | не | По подразбиране е `true` |
| `connect_tone_enabled` | булево | не | По подразбиране е `false` |
| `voicemail_action` | низ | не | `prompt` (по подразбиране), `hangup` или `message` |
| `voicemail_message` | низ | не | Използва се, когато `voicemail_action="message"` |
| `agent_name` | низ | не | Показвано име, изпращано към таблата за управление и уиджета |
| `org_name` | низ | не | Показвано име на организацията за персоната на агента |
| `tools` | масив | не | Вградени схеми за функционални инструменти (вижте [Функционални инструменти](/bg/tools/overview)) |
| `call_id` | цяло число | не | Незадължително ехо на идентификатора на обаждането от заявката; игнорира се |

<Note>
  Непознатите ключове от най-горно ниво се **игнорират** без известие — поле
  с печатна грешка не отхвърля конфигурацията, но просто не се прилага. Редът
  на говорене и `max_hold_seconds` не се приемат тук; те могат да се
  конфигурират само за самия [агент](/api-reference/agents).
</Note>

Тъй като `prompt` и `voice` са задължителни, връщането на `{}` или на отговор,
който не преминава валидация, отхвърля обаждането с `422` — по този път няма
резервен статичен агент (номер или ключ в режим на уебхук няма назначен агент).

---

## Ограничение на размера на отговора

<Warning>
  Отговорите на конфигурацията са ограничени до **5 MiB**. Ако обработчик
  върне по-голям отговор, включително със статус `2xx`,
  ThunderPhone съобщава, че отговорът е надвишил ограничението, и
  отхвърля сесията за обаждането или уиджета. Ограничете отговора до полетата,
  нужни за настройване на обаждането; хоствайте големи данни чрез функционални инструменти или
  друга услуга, вместо да ги вграждате в конфигурацията.
</Warning>

---

## Примерен обработчик

<CodeGroup>
```python Python (FastAPI)
import hashlib
import hmac
import json
import os

from fastapi import FastAPI, HTTPException, Request

app = FastAPI()
WEBHOOK_SECRET = os.environ["THUNDERPHONE_WEBHOOK_SECRET"]

def verify(body: bytes, signature: str) -> bool:
    expected = hmac.new(WEBHOOK_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"] == "telephony.incoming":
        caller = event["data"]["from_number"]
        prompt = (
            "Greet the caller as a San Francisco local…"
            if caller.startswith("+1415")
            else "You are a friendly customer support agent…"
        )
        return {
            "prompt": prompt,
            "voice": "john",
            "product": "spark",
        }
    if event["type"] == "web.incoming":
        return {
            "prompt": "You are the website's helpful voice assistant…",
            "voice": "john",
            "product": "spark",
        }
    return {}
```

```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" }),
  (req, res) => {
    if (!verify(req.body, req.header("X-ThunderPhone-Signature"))) {
      return res.sendStatus(401);
    }
    const event = JSON.parse(req.body.toString("utf8"));

    if (event.type === "telephony.incoming" || event.type === "web.incoming") {
      const caller = event.data.from_number || "web";
      const prompt = caller.startsWith("+1415")
        ? "Greet the caller as a San Francisco local…"
        : "You are a friendly customer support agent…";
      return res.json({
        prompt,
        voice: "john",
        product: "spark",
      });
    }
    res.json({});
  },
);
```
</CodeGroup>

---

## Отговор с функционални инструменти

Прикачете инструменти, за да може AI да извиква вашите API по време на разговора:

```json
{
  "prompt":  "You are a booking assistant. Use the available tools to help customers schedule appointments.",
  "voice":   "john",
  "product": "spark",
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "search_appointments",
        "description": "Find available appointment slots",
        "parameters": {
          "type": "object",
          "properties": {
            "date": { "type": "string", "description": "YYYY-MM-DD" },
            "service": { "type": "string" }
          },
          "required": ["date"]
        }
      },
      "endpoint": {
        "url": "https://api.example.com/appointments/search",
        "method": "POST",
        "headers": {
          "X-Api-Key": "your-key"
        }
      }
    }
  ]
}
```

<Tip>
  Заявките към крайните точки на инструментите се подписват със **същата
  тайна за уебкука на организацията**, с която е подписан този обмен. Вижте
  [Функционални инструменти](/bg/tools/overview) за точната структура и формата
  на подписаната заявка.
</Tip>

---

## Кратка справка за продуктовите нива

| Продукт | Закъснение | Разсъждение | Потвърждение |
|---------|------------|-------------|--------------|
| `spark` | Най-ниско | Базово | — |
| `bolt` | Ниско | Подобрено | — |
| `storm-base` | Средно | Силно | — |
| `storm-base-with-ack` | Средно | Силно | Автоматично запълване, докато мисли |
| `storm-extra` | По-високо | Задълбочено | — |
| `storm-extra-with-ack` | По-високо | Задълбочено | Автоматично запълване, докато мисли |

---

## Свързани

<CardGroup cols={2}>
  <Card title="telephony.complete / web.complete" icon="phone-slash" href="/bg/webhooks/call-complete">
    Неблокиращото събитие при приключване на разговор.
  </Card>
  <Card title="Инструменти за функции" icon="screwdriver-wrench" href="/bg/tools/overview">
    Пълна JSON схема за `tools[]` и договорът за подписания крайна точка.
  </Card>
  <Card title="Webhook крайни точки" icon="bolt" href="/bg/webhooks/endpoints">
    Абонирайте няколко URL адреса за `telephony.incoming` / `web.incoming`.
  </Card>
  <Card title="Динамична конфигурация на разговори" icon="wand-magic-sparkles" href="/bg/guides/dynamic-call-config">
    Шаблони за подкани, инструменти и A/B тестове за всеки обаждащ се.
  </Card>
</CardGroup>
