---
title: "telephony.incoming / web.incoming"
description: "ब्लॉकिंग वेबहुक जो रियल टाइम में इनबाउंड कॉल के कॉन्फ़िगरेशन को आकार देता है।"
---

जब कोई इनबाउंड फोन कॉल **बिना असाइन किए गए
एजेंट** वाले नंबर पर पहुंचती है, या वेब विजेट सेशन
`mode="webhook"` में किसी पब्लिशेबल की पर शुरू होता है, तो ThunderPhone आपके
[लीगेसी वेबहुक URL](/api-reference/organizations#legacy-single-url-webhook)
को एक **ब्लॉकिंग** `telephony.incoming` / `web.incoming` रिक्वेस्ट भेजता है
और कॉन्फ़िगरेशन रिस्पॉन्स की प्रतीक्षा करता है: फोन कॉल के लिए अधिकतम **13 सेकंड**,
जिसमें एक रीट्राई शामिल है, और विजेट सेशन के लिए अधिकतम **10 सेकंड**
([टाइमआउट और रीट्राई](#timeouts-and-retries) देखें)। हर कॉल के लिए प्रॉम्प्ट, वॉइस,
और टूल्स को डायनामिक रूप से चुनने के लिए इस एक्सचेंज का उपयोग करें —
एंड-टू-एंड पैटर्न के लिए [डायनामिक कॉल कॉन्फ़िगरेशन गाइड](/hi/guides/dynamic-call-config)
देखें।

<Note>
  सब्सक्राइब किए गए [वेबहुक एंडपॉइंट्स](/hi/webhooks/endpoints) को भी
  `telephony.incoming` / `web.incoming` प्राप्त होते हैं — **हर** इनबाउंड कॉल
  और वेब सेशन के लिए, चाहे एजेंट कॉन्फ़िगर किया गया हो या नहीं — लेकिन ये
  डिलीवरी `event_id` के साथ फायर-एंड-फॉरगेट नोटिफ़िकेशन होती हैं, कभी
  ब्लॉकिंग नहीं। केवल लेगेसी सिंगल-URL वेबहुक में इस पेज का कॉन्फ़िगरेशन
  एक्सचेंज होता है। एंडपॉइंट नोटिफ़िकेशन के स्वरूप
  [इवेंट्स कैटलॉग](/hi/webhooks/events) में दिए गए हैं।
</Note>

## टाइमआउट और रिट्राइ

जल्दी जवाब दें: आपके निर्णय लेने के दौरान कॉलर लाइन पर इंतज़ार कर रहा है।

फोन कॉल (`telephony.incoming`) के लिए:

- पहले प्रयास में **10 सेकंड** तक लग सकते हैं।
- अगर टाइमआउट होता है, कनेक्ट नहीं हो पाता, या `5xx`, `408` या `429`
  रिस्पॉन्स मिलता है, तो ThunderPhone एक बार फिर कोशिश करता है। रिट्राइ को पूरे एक्सचेंज के लिए **13-सेकंड** के बजट में बचा हुआ समय मिलता है: टाइमआउट हुए पहले प्रयास के बाद लगभग 3 सेकंड, तेज़ विफलता के बाद लगभग पूरे 13 सेकंड।
  अगर 2 सेकंड से कम समय बचता है, तो रिट्राइ नहीं किया जाता।
- कोई भी अन्य `4xx` रिस्पॉन्स, [साइज़ सीमा](#response-size-limit) से बड़ा
  रिस्पॉन्स, या ऐसा `2xx` जिसका बॉडी मान्य कॉन्फ़िगरेशन नहीं है, अंतिम माना जाता है और उस पर रिट्राइ नहीं होता।
- दोनों प्रयास एक ही बॉडी, एक ही `X-ThunderPhone-Signature`,
  और एक ही `X-ThunderPhone-Idempotency-Key` हेडर
  (`telephony-incoming-<call_id>`) भेजते हैं, इसलिए साइड इफेक्ट्स वाला
  हैंडलर रिट्राइ को पहचान सकता है।

कोई फॉलबैक एजेंट नहीं है। अगर उपयोग योग्य कॉन्फ़िगरेशन नहीं मिलता, तो कॉलर को साइलेंट लाइन पर छोड़ने के बजाय कॉल तुरंत समाप्त कर दी जाती है। यह कॉल हिस्ट्री में `end_reason` `inbound_config_webhook_failed` के साथ एक असफल, बिना बिल वाली कॉल के रूप में दिखाई देती है, और सामान्य
[`telephony.complete`](/hi/webhooks/call-complete) इवेंट भेजा जाता है।

विजेट सेशन (`web.incoming`) को 10 सेकंड तक का केवल एक प्रयास मिलता है। अगर यह विफल होता है, तो सेशन रिक्वेस्ट `502` या `422` के साथ विफल होती है।

<Warning>
  **वेबहुक-कॉन्फ़िगर की गई कॉल में ThunderPhone की सहमति
  घोषणा शामिल नहीं होती।** इस एक्सचेंज के माध्यम से कॉन्फ़िगर की गई कॉल
  एजेंट-स्तर की कॉल-आरंभ घोषणा को बायपास करती हैं और ThunderPhone के
  सहमति-घोषणा फ़्रेमवर्क (सेवा की शर्तें, "रिकॉर्डिंग और सहमति" सेक्शन) से
  स्पष्ट रूप से बाहर हैं। इन कॉल पर आवश्यक हर रिकॉर्डिंग, मॉनिटरिंग,
  AI-भागीदारी और कॉलर-पहचान सूचना व सहमति के लिए केवल आपका संगठन
  ज़िम्मेदार है — कॉल को फिर भी रिकॉर्ड, ट्रांसक्राइब, विश्लेषित और AI द्वारा
  संचालित किया जा सकता है। इस पथ को सक्षम करने से पहले आवश्यक खुलासों को
  अपने कॉल फ़्लो में शामिल करें।
</Warning>

## रिक्वेस्ट पेलोड

फ़ोन कॉल (`telephony.incoming`) के लिए:

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

| फ़ील्ड | टाइप | विवरण |
|-------|------|-------------|
| `call_id` | integer | कॉल id — इस कॉल के सभी इवेंट्स में स्थिर |
| `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` | इंटीजर | कॉल आईडी |
| `origin_domain` | स्ट्रिंग | विजेट होस्ट करने वाले पेज का ओरिजिन, जैसा ब्राउज़र ने भेजा है। कोई नॉन-ब्राउज़र क्लाइंट कोई भी वैल्यू भेज सकता है, इसलिए इसे इस बात के प्रमाण के रूप में न मानें कि रिक्वेस्ट कहाँ से आई है |
| `publishable_key_prefix` | स्ट्रिंग | सेशन खोलने वाली publishable key के शुरुआती कैरेक्टर |
| `language`, `primary_language` | स्ट्रिंग | विजेट सेशन द्वारा भाषा ओवरराइड का अनुरोध करने पर मौजूद होता है |
| `voice` | स्ट्रिंग | विजेट सेशन द्वारा वॉइस ओवरराइड का अनुरोध करने पर मौजूद होता है |
| `website_context` | स्ट्रिंग | विजेट द्वारा प्रति-सेशन पेज कॉन्टेक्स्ट भेजने पर मौजूद होता है |

ओवरराइड फ़ील्ड (`language`, `voice`, `website_context`, और कोई भी
ब्राउज़र `variables`) केवल तब आते हैं जब publishable key उन्हें अपने
[ब्राउज़र ओवरराइड्स](/hi/guides/embed-web-widget) में अनुमति देती है। ऐसा सेशन रिक्वेस्ट जिसमें ऐसी कोई फ़ील्ड हो जिसकी key अनुमति नहीं देती, इस webhook के कॉल होने से पहले अस्वीकार कर दिया जाता है।

<Note>
  वेबहुक-मोड विजेट इस रिक्वेस्ट को सेट होने पर publishable key के अपने
  `webhook_url` पर भेजते हैं और अन्यथा संगठन-स्तर के वेबहुक URL पर फ़ॉलबैक
  करते हैं। दोनों ही स्थितियों में इस पर संगठन के वेबहुक `secret` से साइन
  किया जाता है।
</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`। जब कॉल किसी अन्य भाषा में स्विच होती है, तो कॉन्फ़िगर की गई वॉइस रखने के बजाय उस भाषा की मूल वॉइस पर स्विच करें (लिंग के अनुसार मिलान किया गया) |
| `language_switching` | स्ट्रिंग \| null | नहीं | `ask_first` (डिफ़ॉल्ट) या `follow_caller`; `null`, `ask_first` के समान है। बहुभाषी एजेंट के लिए यह निर्धारित करता है कि दूसरा व्यक्ति उसकी किसी अन्य भाषा में बोले तो कैसे संभालना है। `ask_first` भाषा का अनुरोध करने या उसमें पूरा वाक्य बोलने पर तुरंत स्विच करता है, और “हाँ” जैसी छोटी बात के बाद पूछता है कि क्या उसी भाषा में जारी रखना है। `follow_caller` उनके द्वारा बोली गई किसी भी कॉन्फ़िगर की गई भाषा में स्विच करता है, भले ही वे केवल एक शब्द बोलें। केवल तब लागू होता है जब `additional_languages` सेट हो |
| `background_track` | स्ट्रिंग \| null | नहीं | एम्बिएंट ऑडियो आईडी या `null` |
| `acknowledgement_prompt_mode` | स्ट्रिंग | नहीं | `auto` (डिफ़ॉल्ट) या `manual` (Storm-with-ack उत्पाद) |
| `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` |
| `pronunciation_dicts` | बूलियन \| null | नहीं | डिफ़ॉल्ट `false`; `null`, `false` के समान है। `true` होने पर, कॉल का Cartesia स्पीच कॉल की भाषा के लिए ThunderPhone की उच्चारण डिक्शनरी का उपयोग करता है, जहाँ उपलब्ध हो। फ़ोन और विजेट कॉल के लिए काम करता है। केवल ThunderPhone की अपनी Cartesia वॉइस पर लागू होता है, आपके स्वयं के Cartesia API key की वॉइस पर नहीं। `agent_id` के साथ उपयोग नहीं होता, जहाँ सेव किए गए एजेंट की सेटिंग्स लागू होती हैं |
| `voicemail_action` | स्ट्रिंग | नहीं | `prompt` (डिफ़ॉल्ट), `hangup`, या `message` |
| `voicemail_message` | स्ट्रिंग | नहीं | `voicemail_action="message"` होने पर उपयोग किया जाता है |
| `agent_name` | स्ट्रिंग | नहीं | डैशबोर्ड्स और विजेट में रिपोर्ट किया गया डिस्प्ले नाम |
| `org_name` | स्ट्रिंग | नहीं | एजेंट के पर्सोना के लिए संगठन का डिस्प्ले नाम |
| `tools` | ऐरे | नहीं | इनलाइन फ़ंक्शन-टूल स्कीमा ([Function Tools](/hi/tools/overview) देखें) |
| `transfer_destinations` | ऑब्जेक्ट की ऐरे \| null | नहीं | इस कॉल को ट्रांसफ़र किए जा सकने वाले अधिकतम 50 `{name, number}` एंट्री, जिन्हें एजेंट के [ट्रांसफ़र नंबरों](/api-reference/agents#transfer-numbers) की तरह वेलिडेट किया जाता है। एजेंट नाम से और केवल इन्हीं पर ट्रांसफ़र करता है; `[]` का अर्थ है कोई ट्रांसफ़र नहीं। एजेंट को अपने चुने नंबर पर ट्रांसफ़र करने देने के लिए इसे छोड़ दें या `null` भेजें |
| `timezone` | स्ट्रिंग | नहीं | इस कॉल के लिए IANA टाइम ज़ोन, जैसे `America/Chicago`। एजेंट अपनी स्वयं की टाइम ज़ोन के बजाय इसमें तारीख और समय बताता है। `agent_id` के साथ भी अनुमत है। जो मान IANA ज़ोन नहीं हैं, उन्हें अनदेखा किया जाता है। [हर कॉल के लिए टाइम ज़ोन सेट करें](/hi/guides/dynamic-call-config) देखें |
| `call_id` | इंटीजर | नहीं | अनुरोध की कॉल आईडी का वैकल्पिक इको; अनदेखा किया जाता है |

<Note>
  अज्ञात टॉप-लेवल कीज़ को चुपचाप **अनदेखा किया जाता है** — टाइपो वाले फ़ील्ड
  नाम से कॉन्फ़िग अस्वीकार नहीं होता, वह बस लागू नहीं होता। स्पीक-ऑर्डर
  और `max_hold_seconds` यहाँ स्वीकार नहीं किए जाते; इन्हें केवल
  [Agent](/api-reference/agents) पर कॉन्फ़िगर किया जा सकता है।
</Note>

क्योंकि `prompt` और `voice` आवश्यक हैं, `{}` या वेलिडेशन में विफल कोई भी
रिस्पॉन्स लौटाने पर कॉल अस्वीकार हो जाती है: फोन कॉल
[टाइमआउट और रिट्राई](#timeouts-and-retries) में बताए अनुसार समाप्त हो जाती है, और
विजेट सेशन अनुरोध `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>
  टूल-एंडपॉइंट रिक्वेस्ट पर उसी **संगठन वेबहुक
  सीक्रेट** से साइन किया जाता है जिससे इस एक्सचेंज पर साइन किया गया था। सटीक
  संरचना और साइन किए गए रिक्वेस्ट फ़ॉर्मेट के लिए
  [फंक्शन टूल्स](/hi/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="/hi/webhooks/call-complete">
    नॉन-ब्लॉकिंग कॉल-समाप्ति इवेंट।
  </Card>
  <Card title="फ़ंक्शन टूल्स" icon="screwdriver-wrench" href="/hi/tools/overview">
    `tools[]` और साइन किए गए एंडपॉइंट कॉन्ट्रैक्ट के लिए पूर्ण JSON स्कीमा।
  </Card>
  <Card title="वेबहुक एंडपॉइंट्स" icon="bolt" href="/hi/webhooks/endpoints">
    `telephony.incoming` / `web.incoming` के लिए कई URLs सब्सक्राइब करें।
  </Card>
  <Card title="डायनेमिक कॉल कॉन्फ़िगरेशन" icon="wand-magic-sparkles" href="/hi/guides/dynamic-call-config">
    प्रति-कॉलर प्रॉम्प्ट्स, टूल्स और A/B टेस्ट के पैटर्न।
  </Card>
</CardGroup>
