> ## Documentation Index
> Fetch the complete documentation index at: https://docs.thunderphone.com/llms.txt
> Use this file to discover all available pages before exploring further.

# वेबहुक्स अवलोकन

> ThunderPhone रीयल-टाइम इवेंट्स कैसे डिलीवर करता है, सिग्नेचर कैसे सत्यापित करें, और लेगेसी व एंडपॉइंट-आधारित डिलीवरी मॉडल की तुलना।

ThunderPhone आपके सर्वर को HTTP `POST` अनुरोध भेजता है जब कॉल के दौरान घटनाएं होती हैं — इनबाउंड कॉल शुरू होती है, कॉल समाप्त होती है, ग्रेडिंग रन पूरा होता है, अलर्ट ट्रिगर होता है, आदि। **दो डिलीवरी मॉडल** हैं:

<CardGroup cols={2}>
  <Card title="Webhook एंडपॉइंट्स (अनुशंसित)" icon="bolt" href="/hi/webhooks/endpoints">
    कई URL, प्रति-एंडपॉइंट सीक्रेट्स, प्रति-एंडपॉइंट इवेंट फ़िल्टर,
    और ऑटोमैटिक रिट्राइ।
    `GET/POST/PATCH/DELETE /v1/developer/webhook-endpoints` के माध्यम से प्रबंधित करें।
  </Card>

  <Card title="सिंगल-URL लेगसी webhook" icon="link" href="/api-reference/organizations#legacy-single-url-webhook">
    प्रति संगठन एक URL। इसमें **ब्लॉकिंग** कॉन्फ़िगरेशन एक्सचेंज सहित
    कॉल-लाइफसाइकल इवेंट शामिल होते हैं। `GET/PUT /v1/webhook` पर प्रबंधित किया जाता है।
  </Card>
</CardGroup>

[इवेंट्स कैटलॉग](/hi/webhooks/events) के सभी दस इवेंट प्रकार webhook एंडपॉइंट्स के माध्यम से
डिलीवर किए जाते हैं। छह कॉल-लाइफसाइकल इवेंट
(`telephony.incoming`, `telephony.complete`, `telephony.tool`,
`web.incoming`, `web.complete`, `web.tool`) **भी** लेगसी सिंगल-URL webhook को भेजे जाते हैं —
यदि आपके पास लेगसी URL और एक मैचिंग एंडपॉइंट दोनों हैं, तो आपको इवेंट **दोनों** पाथ पर प्राप्त होता है।
ब्लॉकिंग व्यवहार ([
`telephony.incoming` / `web.incoming` कॉन्फ़िगरेशन एक्सचेंज](/hi/webhooks/call-incoming) और webhook-मोड
[टूल डिस्पैच](/hi/tools/overview)) केवल लेगसी पाथ पर उपलब्ध है; प्रत्येक एंडपॉइंट
डिलीवरी एक fire-and-forget नोटिफ़िकेशन है।

## Payload फ़ॉर्मैट

एंडपॉइंट डिलीवरी `data`, `event_id`, और `type` वाला एक JSON ऑब्जेक्ट होती है:

```json theme={null}
{
  "data": {
    "call_id": 987654321,
    "from_number": "+14155550199",
    "to_number": "+15551234567"
  },
  "event_id": "3f6b2ad0-1c9e-4a57-9f2b-8f6f0f9d2f11",
  "type": "telephony.incoming"
}
```

`event_id` प्रत्येक उत्सर्जित इवेंट के लिए यूनिक है। यह रिट्राइ के दौरान
**और** इवेंट प्राप्त करने वाले हर एंडपॉइंट पर समान रहता है — इसके आधार पर डीडुप्लिकेट करें।

लेगसी सिंगल-URL webhook समान `type` और `data` भेजता है, लेकिन
`event_id` के **बिना**:

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

वायर पर, हर बॉडी कैनॉनिकली सीरियलाइज़ होती है — कीज़ को वर्णानुक्रम में सॉर्ट किया जाता है,
कोई व्हाइटस्पेस नहीं होता, और UTF-8 का उपयोग होता है। इन डॉक्यूमेंट्स में प्रिटी-प्रिंट किए गए उदाहरण
केवल पठनीयता के लिए हैं।

इवेंट प्रकारों और payload फ़ील्ड्स की पूरी सूची के लिए [इवेंट्स कैटलॉग](/hi/webhooks/events) देखें।

## सिग्नेचर सत्यापन

हर रिक्वेस्ट में `X-ThunderPhone-Signature` हेडर में **रॉ रिक्वेस्ट
बॉडी** पर एक HMAC-SHA256 सिग्नेचर होता है। साइनिंग key एंडपॉइंट का
`secret` है (या लेगेसी डिलीवरी के लिए आपका संगठन-स्तरीय webhook
`secret`)।

### चरण

1. किसी भी पार्सिंग से **पहले** रॉ रिक्वेस्ट बॉडी पढ़ें।
2. `hmac_sha256(secret, body).hexdigest()` की गणना करें।
3. `X-ThunderPhone-Signature` हेडर से कॉन्स्टेंट टाइम में तुलना करें।

हम ठीक वही बाइट्स साइन करते हैं जो हम भेजते हैं, और वे बाइट्स
कैनॉनिकल JSON सीरियलाइज़ेशन हैं (सॉर्ट की गई keys, कॉम्पैक्ट सेपरेटर)। इसलिए
रॉ बॉडी के विरुद्ध सत्यापन हमेशा काम करता है — और यदि आपका फ्रेमवर्क
आपको केवल पार्स किया हुआ JSON देता है, तो उसे सॉर्ट की गई keys और
कॉम्पैक्ट सेपरेटर के साथ फिर से सीरियलाइज़ करने पर समान बाइट्स बनती हैं। दोनों रेसिपी
[सत्यापन गाइड](/hi/guides/verify-webhook-signatures) में दी गई हैं।

<CodeGroup>
  ```python Python theme={null}
  import hmac
  import hashlib

  def verify_signature(body: bytes, signature: str, secret: str) -> bool:
      expected = hmac.new(
          secret.encode("utf-8"),
          body,
          hashlib.sha256,
      ).hexdigest()
      return hmac.compare_digest(expected, signature or "")

  # Example Flask handler
  from flask import Flask, request, abort
  app = Flask(__name__)

  @app.post("/thunderphone-webhook")
  def handle():
      body = request.get_data()
      sig = request.headers.get("X-ThunderPhone-Signature", "")
      if not verify_signature(body, sig, WEBHOOK_SECRET):
          abort(401)
      event = request.get_json()
      # dispatch on event["type"] …
      return "", 204
  ```

  ```javascript Node.js (Express) theme={null}
  import crypto from "node:crypto";
  import express from "express";

  function verifySignature(body, signature, secret) {
    const expected = crypto
      .createHmac("sha256", secret)
      .update(body)
      .digest("hex");
    if (!signature || expected.length !== signature.length) return false;
    return crypto.timingSafeEqual(
      Buffer.from(expected),
      Buffer.from(signature),
    );
  }

  const app = express();
  app.post(
    "/thunderphone-webhook",
    express.raw({ type: "application/json" }),
    (req, res) => {
      const sig = req.header("X-ThunderPhone-Signature") || "";
      if (!verifySignature(req.body, sig, process.env.WEBHOOK_SECRET)) {
        return res.sendStatus(401);
      }
      const event = JSON.parse(req.body.toString("utf8"));
      // dispatch on event.type …
      res.sendStatus(204);
    },
  );
  ```
</CodeGroup>

## डिलीवरी सेमांटिक्स

ये सेमांटिक्स **endpoint** डिलीवरी पर लागू होते हैं। लेगेसी single-URL
webhook बिना रिट्राई के एक ही synchronous प्रयास करता है।

<AccordionGroup>
  <Accordion title="रिट्राई">
    हर इवेंट का तुरंत एक बार प्रयास किया जाता है। कोई भी `2xx` रिस्पॉन्स
    डिलीवरी को स्वीकार करता है। किसी भी अन्य परिणाम (non-2xx,
    कनेक्शन त्रुटि, timeout) पर हम **पहले प्रयास के 1 m, 5 m, 30 m, 2 h, 6 h,
    12 h, और 24 h बाद** रिट्राई करते हैं — 24 घंटों में
    8 प्रयास। यदि हर प्रयास विफल हो जाता है, तो डिलीवरी रुक जाती है और endpoint
    को [webhook endpoints](/hi/webhooks/endpoints) में
    `status="failing"` के रूप में चिह्नित किया जाता है। पेलोड को स्थायी रूप से स्वीकार करते ही
    `2xx` लौटाएँ; asynchronous रूप से प्रोसेस करें।
  </Accordion>

  <Accordion title="क्रम">
    डिलीवरी क्रम best-effort है। व्यवहार में हम इवेंट को उनके emit होने के
    क्रम में डिलीवर करते हैं, लेकिन विफलता पर रिट्राई क्रम बदल सकते हैं।
    हमेशा `call_id` / object id के आधार पर dedup और reconcile करें।
  </Accordion>

  <Accordion title="डुप्लिकेट">
    डिलीवरी **at-least-once** है: ऐसे रिस्पॉन्स के बाद रिट्राई, जो हमें कभी
    नहीं मिला, किसी इवेंट को डुप्लिकेट कर सकता है। हर रिट्राई में वही
    `event_id` होता है, इसलिए प्रोसेस किए गए ids स्टोर करें और दोहराव छोड़ दें। `event_id`
    endpoints के बीच भी साझा होता है — एक ही इवेंट को subscribe किए गए दो
    endpoints को वही `event_id` मिलता है।
  </Accordion>

  <Accordion title="टाइमआउट">
    Endpoint डिलीवरी में प्रत्येक प्रयास के लिए **30 s** timeout होता है। लेगेसी
    पथ पर, लाइव कॉल व्यवहार नियंत्रित करने वाले blocking requests —
    [`telephony.incoming` / `web.incoming`](/hi/webhooks/call-incoming)
    configuration exchange — **10 s** के बाद timeout हो जाते हैं, लेकिन धीमा
    रिस्पॉन्स कॉल पिकअप में देरी करता है, इसलिए कुछ सेकंड के भीतर उत्तर देने का
    लक्ष्य रखें। Webhook-mode [tool dispatch](/hi/tools/overview) 20 s की अनुमति देता है।
  </Accordion>

  <Accordion title="स्रोत IPs">
    आउटबाउंड webhooks ThunderPhone की cloud IP रेंज से उत्पन्न होते हैं।
    यदि आपके firewall को allowlist की आवश्यकता है, तो support से संपर्क करें और हम
    वर्तमान रेंज साझा करेंगे।
  </Accordion>
</AccordionGroup>

## लेगेसी और endpoint-आधारित webhooks के बीच चयन

| सुविधा                   | लेगेसी (`/v1/webhook`)                                                    | Endpoints (`/v1/developer/webhook-endpoints`) |
| ------------------------ | ------------------------------------------------------------------------- | --------------------------------------------- |
| URLs की संख्या           | प्रति संगठन 1                                                             | प्रति संगठन कई                                |
| इवेंट कवरेज              | केवल `telephony.*` / `web.*`                                              | सभी 10 इवेंट प्रकार                           |
| इवेंट फ़िल्टर            | —                                                                         | प्रति-endpoint                                |
| रिट्राई                  | कोई नहीं                                                                  | 24 h में 8 प्रयास                             |
| Envelope                 | `type` + `data`                                                           | `type` + `data` + `event_id`                  |
| Secret rotation          | एकल secret को बदलता है                                                    | प्रति-endpoint secret                         |
| हटाए बिना निष्क्रिय करें | —                                                                         | `status=disabled`                             |
| स्टेटस दृश्यता           | —                                                                         | `active` / `disabled` / `failing`             |
| Blocking config exchange | हाँ ([`telephony.incoming` / `web.incoming`](/hi/webhooks/call-incoming)) | कभी नहीं — केवल notifications                 |
| इनके लिए सबसे उपयुक्त    | डायनामिक कॉल configuration                                                | प्रोडक्शन में इवेंट consumption               |

नई integrations को endpoint-आधारित
webhooks के माध्यम से इवेंट consume करने चाहिए। लेगेसी URL केवल तभी रखें (या जोड़ें) जब आप कॉल
को पिकअप समय पर डायनामिक रूप से configure करते हैं या webhook-mode tool dispatch का उपयोग करते हैं — वे
request/response exchanges केवल लेगेसी पथ पर चलते हैं।

***

## संबंधित

<CardGroup cols={2}>
  <Card title="इवेंट कैटलॉग" icon="list" href="/hi/webhooks/events">
    सभी इवेंट प्रकार और उनके पेलोड।
  </Card>

  <Card title="Webhook endpoints" icon="bolt" href="/hi/webhooks/endpoints">
    कई endpoints, इवेंट फ़िल्टर और secrets प्रबंधित करें।
  </Card>

  <Card title="telephony.incoming / web.incoming" icon="phone" href="/hi/webhooks/call-incoming">
    कॉल configure करने के लिए आपके सर्वर को जिस blocking request का उत्तर देना होगा।
  </Card>

  <Card title="telephony.complete / web.complete" icon="phone" href="/hi/webhooks/call-complete">
    ट्रांसक्रिप्ट, रिकॉर्डिंग और metrics के साथ कॉल के बाद का पेलोड।
  </Card>
</CardGroup>
