---
title: "डायनेमिक प्रति-कॉल कॉन्फ़िगरेशन"
description: "आपके नियंत्रित वेबहुक में कस्टम लॉजिक द्वारा संचालित, हर इनकमिंग कॉल के लिए अलग से उत्तर देने वाला एजेंट चुनें — या उसका प्रॉम्प्ट और सेटिंग्स फिर से लिखें।"
---

डिफ़ॉल्ट रूप से हर फ़ोन नंबर और पब्लिशेबल की को एक स्टैटिक एजेंट
असाइन किया जाता है। जब आपको **हर कॉलर के लिए** या **हर विज़िटर के लिए** कस्टमाइज़ेशन
चाहिए — VIP रूटिंग, लॉग-इन किए हुए यूज़र का कॉन्टेक्स्ट, A/B प्रॉम्प्ट टेस्ट — तो
वेबहुक मोड पर स्विच करें और अपने सर्वर को निर्णय लेने दें।

## यह कैसे काम करता है

1. आप [`telephony.incoming`](/hi/webhooks/events)
   (फोन) या [`web.incoming`](/hi/webhooks/events) (विजेट)
   इवेंट की सदस्यता लेते हैं। दोनों **ब्लॉकिंग** वेबहुक हैं: ThunderPhone
   कॉल जारी रखने से पहले आपके रिस्पॉन्स का इंतज़ार करता है—फोन कॉल के लिए
   अधिकतम 13 सेकंड (एक रीट्राई सहित) और विजेट सेशन के लिए 10 सेकंड।
2. ThunderPhone आपको `{call_id, from_number, to_number}` भेजता है (विजेट
   सेशन में नंबरों के बजाय विजेट-विशिष्ट फ़ील्ड होते हैं—[रिक्वेस्ट स्कीमा](/hi/webhooks/call-incoming)
   देखें)।
3. आपका सर्वर एजेंट कॉन्फ़िगरेशन (प्रॉम्प्ट, वॉइस, प्रोडक्ट, टूल्स) के साथ रिस्पॉन्स देता है।
   ThunderPhone कॉल के लिए उस कॉन्फ़िगरेशन का उपयोग करता है।
4. कोई फ़ॉलबैक एजेंट नहीं है। यदि आप `{}` या अमान्य कॉन्फ़िगरेशन लौटाते हैं,
   या [रीट्राई](/hi/webhooks/call-incoming) के बाद भी रिक्वेस्ट
   विफल रहती है, तो फोन कॉल तुरंत समाप्त कर दी जाती है और `end_reason`
   `inbound_config_webhook_failed` के साथ रिकॉर्ड की जाती है; विजेट सेशन रिक्वेस्ट विफल हो जाती है।

<Note>
  फ़ोन कॉल (`telephony.incoming`) और विजेट
  सेशन (`web.incoming`) के लिए समान रूप से काम करता है, चाहे वे वेबहुक एंडपॉइंट
  पर डिलीवर किए जाएँ या लेगेसी सिंगल-URL वेबहुक पर।
</Note>

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

## 1. वेबहुक डेस्टिनेशन कॉन्फ़िगर करें

<Tabs>
<Tab title="फ़ोन कॉल">
फ़ोन नंबरों के लिए, अपने एंडपॉइंट को `telephony.incoming` के लिए सब्सक्राइब करें:

```bash
curl -X POST https://api.thunderphone.com/v1/developer/webhook-endpoints \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "label":  "Prod call-incoming",
    "url":    "https://example.com/thunderphone/incoming",
    "events": ["telephony.incoming"]
  }'
```

रिस्पॉन्स में एक वन-शॉट `secret` शामिल होता है — इसे सेव करें; आप इसका उपयोग
सिग्नेचर वेरिफ़िकेशन के लिए करेंगे।
</Tab>
<Tab title="वेब विजेट">
विजेट सेशन के लिए, अपने एंडपॉइंट URL के साथ `mode="webhook"` में एक पब्लिशेबल की बनाएँ:

```bash
curl -X POST https://api.thunderphone.com/v1/publishable-key \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name":            "Dynamic widget",
    "mode":            "webhook",
    "webhook_url":     "https://example.com/thunderphone/widget-incoming",
    "allowed_domains": ["example.com"]
  }'
```

हर सेशन शुरू होने पर विजेट इस URL पर POST करेगा।
</Tab>
</Tabs>

## 2. हैंडलर लागू करें

तीन सामान्य नियम:

- हर अनुरोध पर **सिग्नेचर सत्यापित करें** (देखें
  [वेबहुक सिग्नेचर सत्यापित करें](/hi/guides/verify-webhook-signatures)).
  डेवलपमेंट में इसे न छोड़ें — इसे एक बार सही करें और दोबारा इस्तेमाल करें।
- **तेज़ी से जवाब दें**। फ़ोन कॉल का पहला प्रयास 10 सेकंड पर काट दिया जाता है
  और पूरा एक्सचेंज 13 सेकंड पर, और हर सेकंड कॉलर के लिए खामोशी होता है।
  ज़रूरत हो तो डेटाबेस लुकअप करें, लेकिन डाउनस्ट्रीम LLMs को सिंक्रोनस रूप से कॉल न करें —
  अगर आपको डायनेमिक प्रॉम्प्ट जनरेशन चाहिए, तो पहले से कंप्यूट करें और कैश करें।
- **साफ़ तरीके से फ़ॉलबैक करें**। किसी भी अप्रत्याशित स्थिति के लिए, डिफ़ॉल्ट
  `prompt` और `voice` (या सेव किया हुआ `agent_id`) के साथ जवाब दें। `{}`
  या एरर स्टेटस लौटाने से कॉल समाप्त हो जाती है।

<CodeGroup>
```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, sig: str) -> bool:
    expected = hmac.new(SECRET.encode(), body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, sig or "")

@app.post("/thunderphone/incoming")
async def incoming(request: Request):
    body = await request.body()
    if not verify(body, request.headers.get("X-ThunderPhone-Signature", "")):
        raise HTTPException(401)

    event = json.loads(body)
    if event["type"] not in ("telephony.incoming", "web.incoming"):
        return {}  # fall back to default

    caller = event["data"]["from_number"]
    # Cheap DB lookup: is this a known VIP?
    customer = lookup_customer(caller)
    if customer and customer.tier == "vip":
        return {
            "prompt":  f"You are a VIP concierge for {customer.name}. Be proactive…",
            "voice":   "john",
            "product": "storm-base",
        }
    return {}  # default agent handles non-VIPs

def lookup_customer(phone: str):
    # ... your CRM integration ...
    pass
```

```javascript Express
import crypto from "node:crypto";
import express from "express";

const app = express();
const SECRET = process.env.THUNDERPHONE_WEBHOOK_SECRET;

function verify(body, sig) {
  const expected = crypto.createHmac("sha256", SECRET).update(body).digest("hex");
  return sig &&
    crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(sig));
}

app.post(
  "/thunderphone/incoming",
  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"));

    const IMPORTANT_TYPES = new Set([
      "telephony.incoming",
      "web.incoming",
    ]);
    if (!IMPORTANT_TYPES.has(event.type)) return res.json({});

    const customer = await lookupCustomer(event.data.from_number);
    if (customer?.tier === "vip") {
      return res.json({
        prompt:  `You are a VIP concierge for ${customer.name}. Be proactive…`,
        voice:   "john",
        product: "storm-base",
      });
    }
    res.json({}); // fall back to default agent
  },
);
```
</CodeGroup>

## 3. रिस्पॉन्स स्कीमा

रिस्पॉन्स बॉडी
[इनकमिंग-कॉल रिस्पॉन्स स्कीमा](/hi/webhooks/call-incoming)
से बिल्कुल मेल खाती है। आम तौर पर उपयोग किए जाने वाले फ़ील्ड:

| फ़ील्ड | टाइप | विवरण |
|-------|------|-------------|
| `prompt` | स्ट्रिंग (आवश्यक) | एजेंट के लिए सिस्टम प्रॉम्प्ट |
| `voice` | स्ट्रिंग (आवश्यक) | [`GET /v1/voices`](/api-reference/agents#voices) से वॉइस आईडी |
| `product` | स्ट्रिंग | डिफ़ॉल्ट रूप से `spark`। एक्सपेरिमेंटल प्रोडक्ट केवल अलाउलिस्ट किए गए संगठनों के लिए उपलब्ध हैं। |
| `background_track` | स्ट्रिंग \| null | एम्बिएंट ऑडियो आईडी |
| `acknowledgement_prompt_mode` | स्ट्रिंग | `auto` या `manual` (केवल ack वाले Storm के लिए) |
| `acknowledgement_prompt` | स्ट्रिंग | मोड `manual` होने पर आवश्यक |
| `language_switching` | स्ट्रिंग | बहुभाषी एजेंटों के लिए, `ask_first` या `follow_caller` |
| `tools` | ऐरे | इनलाइन फंक्शन-टूल स्कीमा — [फंक्शन टूल्स](/hi/tools/overview) देखें |

<Note>
  प्रति-कॉल बोलने का क्रम और `max_hold_seconds` वेबहुक रिस्पॉन्स में उपलब्ध नहीं हैं।
  इन्हें उस [एजेंट](/api-reference/agents) पर सेट करें जिसका आप रेफ़रेंस देते हैं।
</Note>

### सेव किया हुआ एजेंट रखें और वेरिएबल्स दें

उस संगठन के सेव किए गए एजेंट को प्रति-कॉल डेटा के साथ उपयोग करने के लिए `{"agent_id": 12, "variables": {"name": "Ada"}}` लौटाएँ। इसके प्रॉम्प्ट में `{{name}}` या
`{{name|Friend}}` हो सकता है। वेबहुक वेरिएबल्स अनुरोध-स्तरीय वेरिएबल्स के ऊपर मर्ज होते हैं; null
प्लेसहोल्डर डिफ़ॉल्ट का उपयोग करता है, या यदि कोई डिफ़ॉल्ट नहीं दिया गया है तो खाली टेक्स्ट का। अंतिम
वैल्यू और अनरिज़ॉल्व्ड नाम कॉल विवरण और कंप्लीशन वेबहुक्स में दिखाई देते हैं।
सेव किए गए एजेंट के रिस्पॉन्स केवल `agent_id`, `variables` और `timezone` स्वीकार करते हैं। यदि `prompt` मौजूद
है, तो रिस्पॉन्स इनलाइन कॉन्फ़िगरेशन का उपयोग करता है और `agent_id` को अनदेखा करता है (जिसमें
null या गैर-पूर्णांक मेटाडेटा शामिल है); इनलाइन प्रॉम्प्ट का फिर भी वैध होना आवश्यक है। इनलाइन
कॉन्फ़िगरेशन रिस्पॉन्स में `variables` भी शामिल हो सकते हैं। सेव किए गए एजेंट के रिस्पॉन्स फ़ोन और विजेट, दोनों कॉल्स पर
एजेंट के डिप्लॉय किए गए A/B स्प्लिट का उपयोग करते हैं, फिर वेरिएबल्स रेंडर करते हैं। सीमाओं और सेशन API समर्थन के लिए [कॉल वेरिएबल्स](/hi/guides/call-variables)
देखें। ब्लॉकिंग कॉन्फ़िगरेशन लेगेसी फ़ोन-नंबर/संगठन URL या वेबहुक-मोड विजेट की से आता है; एंडपॉइंट-सिस्टम
इनकमिंग इवेंट्स केवल नोटिफ़िकेशन हैं।

### हर कॉल के लिए टाइम ज़ोन सेट करें

एक एजेंट अलग-अलग टाइम ज़ोन में मौजूद कॉन्टैक्ट्स के लिए जवाब दे सकता है। किसी सेव किए गए एजेंट या इनलाइन रिस्पॉन्स में IANA नाम `timezone` जोड़ें। एजेंट इस कॉल के लिए तारीख और समय बताता है और एजेंट के अपने टाइम ज़ोन से पहले, उस ज़ोन के समय ऑफ़र करता है:

```json
{"agent_id": 12, "timezone": "America/Chicago", "variables": {"name": "Ada"}}
```

`variables` में टाइमस्टैम्प के बजाय ज़ोन भेजें: कॉल के दौरान एजेंट की घड़ी चलती रहती है, और आपके द्वारा भेजा गया समय पुराना हो जाता है। जो वैल्यू IANA ज़ोन नहीं है उसे अनदेखा कर दिया जाता है और कॉल एजेंट के ज़ोन में कनेक्ट होती है।

## पैटर्न

### लॉग-इन उपयोगकर्ता कॉन्टेक्स्ट

वेबहुक-मोड विजेट्स में, विज़िटर का पेज पहले से जानता है कि वे
कौन हैं। अपने वेबहुक को उस क्वेरी स्ट्रिंग पैरामीटर के साथ कॉल करें जिसे विजेट SDK
फॉरवर्ड करता है (`?customer_id=123`) और ग्राहक को सर्वर-साइड पर लुक अप करें।

### A/B प्रॉम्प्ट रोलआउट

इसे स्वयं बनाने से पहले, ध्यान दें कि ThunderPhone में एक नेटिव
[एक्सपेरिमेंट्स](/hi/guides/concepts) फ़ीचर
(`/dashboard/experiments` और एजेंट बिल्डर का **A/B** टैब) है, जो
वैरिएंट्स परिभाषित करता है, ट्रैफ़िक विभाजित करता है, और प्रत्येक वैरिएंट के परिणामों की तुलना करता है —
वेबहुक की आवश्यकता नहीं है।

यदि फिर भी आपको वेबहुक-साइड कंट्रोल चाहिए: `call_id` → बकेट हैश करें;
`0..49` के लिए प्रॉम्प्ट A और `50..99` के लिए प्रॉम्प्ट B दें। चुने गए
बकेट को अपने DB में रिकॉर्ड करें और बाद में पूर्ण हुई कॉल के ग्रेड से
कोरिलेट करें।

### समय-आधारित रूटिंग

बिज़नेस आवर्स → "लाइव सपोर्ट" एजेंट; आफ्टर-आवर्स → "संदेश लें"
एजेंट। अपने हैंडलर में `new Date().getUTCHours()` पर प्योर स्विच करें।

---

## अगले चरण

<CardGroup cols={2}>
  <Card title="इनकमिंग-कॉल वेबहुक रेफ़रेंस" icon="phone" href="/hi/webhooks/call-incoming">
    हर कॉन्फ़िगरेशन की सहित सटीक रिक्वेस्ट + रिस्पॉन्स स्कीमा।
  </Card>
  <Card title="वेबहुक सिग्नेचर सत्यापित करें" icon="shield-check" href="/hi/guides/verify-webhook-signatures">
    HMAC को एक बार सही करें; हर जगह पुनः उपयोग करें।
  </Card>
  <Card title="टूल इंटीग्रेशन बनाएँ" icon="screwdriver-wrench" href="/hi/guides/build-tool-integration">
    डायनामिक रूटिंग को प्रति-एजेंट टूल्स के साथ संयोजित करें।
  </Card>
  <Card title="डिलीवरी सेमांटिक्स" icon="bolt" href="/hi/webhooks/overview">
    रिट्राई, ऑर्डरिंग, टाइमआउट्स।
  </Card>
</CardGroup>
