> This is a page from the ElevenLabs documentation. For a complete page index, fetch https://elevenlabs.io/docs/llms.txt. For the full documentation in a single file, fetch https://elevenlabs.io/docs/llms-full.txt.

# कॉल के बाद वेबहुक

## परिचय

कॉल के बाद के [वेबहुक](/docs/hi/eleven-api/resources/webhooks) आपको विश्लेषण पूरा होने के बाद कॉल की विस्तृत जानकारी पाने देते हैं। सक्षम होने पर, ElevenLabs आपके तय किए गए एंडपॉइंट पर कॉल के विस्तृत डेटा के साथ एक POST अनुरोध भेजेगा।

ElevenLabs तीन तरह के कॉल के बाद के वेबहुक सपोर्ट करता है:

* **ट्रांसक्रिप्शन वेबहुक** (`post_call_transcription`): ट्रांसक्रिप्ट, विश्लेषण नतीजे और मेटाडेटा सहित बातचीत का पूरा डेटा शामिल होता है
* **ऑडियो वेबहुक** (`post_call_audio`): पूरी बातचीत के base64-एन्कोडेड ऑडियो के साथ न्यूनतम डेटा शामिल होता है
* **कॉल शुरू करने में विफलता के वेबहुक** (`call_initiation_failure`): विफलता के कारणों और मेटाडेटा सहित कॉल शुरू करने के असफल प्रयासों की जानकारी शामिल होती है

## कॉल के बाद के वेबहुक सक्षम करना

कॉल के बाद के वेबहुक आपके वर्कस्पेस के सभी एजेंटों के लिए ElevenAgents के [सेटिंग्स पेज](https://elevenlabs.io/app/agents/settings) से सक्षम किए जा सकते हैं।

![कॉल के बाद वेबहुक सेटिंग्स](/docs/_fern-img/eb5d768612d6461a21bc3127611f60724be3e1a55005af43faf48f2d7bf23807.webp)

> **Warning**
>
> सफल माने जाने के लिए कॉल के बाद के वेबहुक को 200 स्टेटस कोड लौटाना होगा। बार-बार विफल होने वाले वेबहुक अपने-आप अक्षम हो जाते हैं, अगर लगातार 10 या उससे अधिक विफलताएं हों और आखिरी
> सफल डिलीवरी 7 दिन से अधिक पहले हुई हो या कभी सफलतापूर्वक डिलीवर न हुई हो।

> **Note**
>
> कॉल के बाद के वेबहुक विफल होने पर अपने-आप फिर से आज़माए जा सकते हैं। [वेबहुक रीट्राई](/docs/hi/eleven-api/resources/webhooks#retries) देखें।

### प्रमाणीकरण

लिस्नर के लिए सभी इनकमिंग वेबहुक को वैलिडेट करना ज़रूरी है। वेबहुक फ़िलहाल HMAC सिग्नेचर के ज़रिए ऑथेंटिकेशन सपोर्ट करते हैं। HMAC ऑथेंटिकेशन सेट अप करने के लिए:

* वेबहुक बनाते समय जनरेट हुए शेयर किए गए सीक्रेट को सुरक्षित रूप से स्टोर करें
* SDK का इस्तेमाल करके अपने एंडपॉइंट में ElevenLabs-Signature हेडर को वेरिफ़ाई करें

JavaScript SDK में `constructEvent` और Python SDK में **`rawBody`**, **`sig_header`**, और **`secret`** के साथ `construct_event` उपलब्ध है (Python में इनके नाम `payload` / `signature` नहीं हैं)। दोनों सिग्नेचर वेरिफ़ाई करते हैं, टाइमस्टैम्प वैलिडेट करते हैं और JSON पेलोड पार्स करते हैं।

#### Python

FastAPI का इस्तेमाल करने वाले वेबहुक हैंडलर का उदाहरण:

```python
from dotenv import load_dotenv
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
from elevenlabs.client import ElevenLabs
from elevenlabs.errors import BadRequestError
import os

load_dotenv()

app = FastAPI()
elevenlabs = ElevenLabs(
    api_key=os.getenv("ELEVENLABS_API_KEY"),
)

WEBHOOK_SECRET = os.getenv("WEBHOOK_SECRET")

@app.post("/webhook")
async def receive_message(request: Request):
    payload = await request.body()
    signature = request.headers.get("elevenlabs-signature")

    try:
        event = elevenlabs.webhooks.construct_event(
            rawBody=payload.decode("utf-8"),
            sig_header=signature,
            secret=WEBHOOK_SECRET,
        )
    except BadRequestError as e:
        return JSONResponse(content={"error": "Invalid signature"}, status_code=401)

    # construct_event returns a dict (parsed JSON), not an object with attributes
    if event.get("type") == "post_call_transcription":
        print(f"Received transcription: {event.get('data')}")

    return {"status": "received"}
```

#### JavaScript

#### Express

Express का इस्तेमाल करने वाले वेबहुक हैंडलर का उदाहरण:

```javascript
import { ElevenLabsClient } from '@elevenlabs/elevenlabs-js';
import express from 'express';

const app = express();

const elevenlabs = new ElevenLabsClient();
const WEBHOOK_SECRET = process.env.WEBHOOK_SECRET;

// Use express.text() to preserve raw body for signature verification
app.post('/webhook', express.text({ type: 'application/json' }), async (req, res) => {
  const signature = req.headers['elevenlabs-signature'];
  const payload = req.body; // Raw string body

  let event;
  try {
    event = await elevenlabs.webhooks.constructEvent(payload, signature, WEBHOOK_SECRET);
  } catch (error) {
    return res.status(401).json({ error: 'Invalid signature' });
  }

  // Process the webhook event
  if (event.type === 'post_call_transcription') {
    console.log('Received transcription:', event.data);
  }

  res.status(200).json({ received: true });
});
```

#### Next.js

Next.js API रूट का इस्तेमाल करने वाले वेबहुक हैंडलर का उदाहरण:

**`app/api/webhook/route.ts`**

```typescript app/api/webhook/route.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
import { ElevenLabsClient } from '@elevenlabs/elevenlabs-js';

const elevenlabs = new ElevenLabsClient();
const WEBHOOK_SECRET = process.env.WEBHOOK_SECRET;

export async function POST(req: NextRequest) {
  const body = await req.text();
  const signature = req.headers.get('elevenlabs-signature');

  let event;
  try {
    event = await elevenlabs.webhooks.constructEvent(body, signature, WEBHOOK_SECRET);
  } catch (error) {
    return NextResponse.json({ error: 'Invalid signature' }, { status: 401 });
  }

  // Process the webhook event
  if (event.type === 'post_call_transcription') {
    console.log('Received transcription:', event.data);
  }

  return NextResponse.json({ received: true }, { status: 200 });
}
```

### IP अलाउलिस्टिंग

अतिरिक्त सुरक्षा के लिए, आप ElevenLabs के स्टैटिक इग्रेस IP को अपनी अलाउलिस्ट में जोड़ सकते हैं। IP पतों की पूरी सूची के लिए [IP अलाउलिस्टिंग](/docs/hi/eleven-api/resources/ip-allowlisting) देखें।

> **Tip**
>
> HMAC सिग्नेचर वैलिडेशन के साथ IP अलाउलिस्टिंग का इस्तेमाल सुरक्षा की कई परतें देता है।

## वेबहुक रिस्पॉन्स संरचना

ElevenLabs तीन अलग-अलग तरह के कॉल के बाद के वेबहुक भेजता है, जिनमें से हर एक की डेटा संरचना अलग है:

### ट्रांसक्रिप्शन वेबहुक (`post_call_transcription`)

इसमें पूरे ट्रांसक्रिप्ट, विश्लेषण नतीजे और मेटाडेटा सहित बातचीत का विस्तृत डेटा शामिल होता है।

#### टॉप-लेवल फ़ील्ड

| फ़ील्ड            | टाइप   | विवरण                                                                     |
| ----------------- | ------ | ------------------------------------------------------------------------- |
| `type`            | string | इवेंट का प्रकार (हमेशा `post_call_transcription`)                         |
| `data`            | object | `ConversationHistoryCommonModel` संरचना का इस्तेमाल करने वाला बातचीत डेटा |
| `event_timestamp` | number | यह इवेंट Unix समय UTC में कब हुआ                                          |

#### डेटा ऑब्जेक्ट संरचना

`data` ऑब्जेक्ट में ये शामिल हैं:

| फ़ील्ड                                | टाइप    | विवरण                                                                  |
| ------------------------------------- | ------- | ---------------------------------------------------------------------- |
| `agent_id`                            | string  | कॉल संभालने वाले एजेंट की ID                                           |
| `agent_name`                          | string  | बातचीत के समय एजेंट का नाम                                             |
| `conversation_id`                     | string  | बातचीत का यूनिक आइडेंटिफ़ायर                                           |
| `status`                              | string  | बातचीत की स्थिति (जैसे, "done")                                        |
| `user_id`                             | string  | उपलब्ध होने पर यूज़र आइडेंटिफ़ायर                                      |
| `branch_id`                           | string  | बातचीत के लिए इस्तेमाल की गई एजेंट ब्रांच, यदि लागू हो                 |
| `version_id`                          | string  | कॉल के दौरान सक्रिय एजेंट वर्शन (स्नैपशॉट) की ID                       |
| `environment`                         | string  | एनवायरनमेंट वेरिएबल रिज़ॉल्व करने के लिए इस्तेमाल किया गया एनवायरनमेंट |
| `transcript`                          | array   | टर्न्स के साथ पूरी बातचीत का ट्रांसक्रिप्ट                             |
| `metadata`                            | object  | कॉल टाइमिंग, लागत और फ़ोन विवरण                                        |
| `analysis`                            | object  | मूल्यांकन नतीजे और बातचीत का सारांश                                    |
| `conversation_initiation_client_data` | object  | कॉन्फ़िगरेशन ओवरराइड और डायनामिक वेरिएबल                               |
| `has_audio`                           | boolean | क्या बातचीत के लिए कोई ऑडियो उपलब्ध है                                 |
| `has_user_audio`                      | boolean | क्या बातचीत के लिए यूज़र ऑडियो उपलब्ध है                               |
| `has_response_audio`                  | boolean | क्या बातचीत के लिए एजेंट रिस्पॉन्स ऑडियो उपलब्ध है                     |

### ऑडियो वेबहुक (`post_call_audio`)

इसमें base64-एन्कोडेड MP3 के रूप में पूरी बातचीत के ऑडियो के साथ न्यूनतम डेटा शामिल होता है।

#### टॉप-लेवल फ़ील्ड

| फ़ील्ड            | टाइप   | विवरण                                     |
| ----------------- | ------ | ----------------------------------------- |
| `type`            | string | इवेंट का प्रकार (हमेशा `post_call_audio`) |
| `data`            | object | न्यूनतम ऑडियो डेटा                        |
| `event_timestamp` | number | यह इवेंट Unix समय UTC में कब हुआ          |

#### डेटा ऑब्जेक्ट संरचना

`data` ऑब्जेक्ट में सिर्फ़ ये शामिल हैं:

| फ़ील्ड            | टाइप   | विवरण                                                                    |
| ----------------- | ------ | ------------------------------------------------------------------------ |
| `agent_id`        | string | कॉल संभालने वाले एजेंट की ID                                             |
| `conversation_id` | string | बातचीत का यूनिक आइडेंटिफ़ायर                                             |
| `full_audio`      | string | MP3 फ़ॉर्मैट में पूरी बातचीत का ऑडियो रखने वाली base64-एन्कोडेड स्ट्रिंग |

> **Warning**
>
> ऑडियो वेबहुक में सिर्फ़ ऊपर सूचीबद्ध तीन फ़ील्ड होते हैं। इनमें ट्रांसक्रिप्ट डेटा,
> मेटाडेटा, विश्लेषण नतीजे या बातचीत के अन्य विवरण शामिल नहीं होते।

### कॉल शुरू करने में विफलता के वेबहुक (`call_initiation_failure`)

इसमें टेलीफ़ोनी कॉल शुरू करने के प्रयासों की जानकारी शामिल होती है, जिसमें विफलता के कारण और टेलीफ़ोनी-प्रोवाइडर मेटाडेटा शामिल हैं।

> **Note**
>
> कॉल शुरू करने में विफलता वाले वेबहुक इवेंट तब भेजे जाते हैं, जब कनेक्शन त्रुटियों,
> यूज़र द्वारा कॉल अस्वीकार करने या यूज़र द्वारा कॉल न उठाने की वजह से कॉल शुरू नहीं हो पाती। अगर कॉल वॉइसमेल पर जाती है या किसी ऑटोमेटेड सर्विस द्वारा उठाई जाती है, तो कॉल शुरू करने में विफलता का वेबहुक नहीं भेजा जाता, क्योंकि कॉल
> सफलतापूर्वक शुरू हो चुकी थी।

#### टॉप-लेवल फ़ील्ड

| फ़ील्ड            | टाइप   | विवरण                                             |
| ----------------- | ------ | ------------------------------------------------- |
| `type`            | string | इवेंट का प्रकार (हमेशा `call_initiation_failure`) |
| `data`            | object | कॉल शुरू करने में विफलता का डेटा                  |
| `event_timestamp` | number | यह इवेंट Unix समय UTC में कब हुआ                  |

#### डेटा ऑब्जेक्ट संरचना

`data` ऑब्जेक्ट में ये शामिल हैं:

| फ़ील्ड            | टाइप   | विवरण                                              |
| ----------------- | ------ | -------------------------------------------------- |
| `agent_id`        | string | कॉल संभालने के लिए असाइन किए गए एजेंट की ID        |
| `conversation_id` | string | बातचीत का यूनिक आइडेंटिफ़ायर                       |
| `failure_reason`  | string | विफलता का कारण ("busy", "no-answer", "unknown")    |
| `metadata`        | object | टेलीफ़ोनी प्रोवाइडर द्वारा दिया गया अतिरिक्त डेटा। |

#### मेटाडेटा ऑब्जेक्ट संरचना

`metadata` ऑब्जेक्ट की संरचना इस बात पर निर्भर करती है कि आउटबाउंड कॉल Twilio के ज़रिए की गई थी या SIP ट्रंकिंग के ज़रिए। ऑब्जेक्ट में एक `type` फ़ील्ड होता है, जो दोनों के बीच अंतर करता है, और एक `body` फ़ील्ड होता है जिसमें प्रोवाइडर-विशिष्ट विवरण होते हैं।

**SIP मेटाडेटा** (`type: "sip"`):

| फ़ील्ड | टाइप   | ज़रूरी | विवरण                          |
| ------ | ------ | ------ | ------------------------------ |
| `type` | string | हाँ    | प्रोवाइडर प्रकार (हमेशा `sip`) |
| `body` | object | हाँ    | SIP-विशिष्ट कॉल विफलता जानकारी |

SIP मेटाडेटा के लिए `body` ऑब्जेक्ट में ये शामिल हैं:

| फ़ील्ड            | टाइप   | ज़रूरी | विवरण                                                                                           |
| ----------------- | ------ | ------ | ----------------------------------------------------------------------------------------------- |
| `from_number`     | number | हाँ    | कॉल शुरू करने वाले पक्ष का फ़ोन नंबर।                                                           |
| `to_number`       | number | हाँ    | जिस पक्ष को कॉल किया गया उसका फ़ोन नंबर।                                                        |
| `sip_status_code` | number | हाँ    | SIP रिस्पॉन्स स्टेटस कोड (जैसे, व्यस्त होने पर 486)                                             |
| `error_reason`    | string | हाँ    | इंसानों के पढ़ने योग्य त्रुटि विवरण                                                             |
| `call_sid`        | string | हाँ    | SIP कॉल सेशन आइडेंटिफ़ायर                                                                       |
| `twirp_code`      | string | नहीं   | लागू होने पर [Twirp त्रुटि कोड](https://twitchtv.github.io/twirp/docs/spec_v7.html#error-codes) |
| `sip_status`      | string | नहीं   | स्टेटस कोड के अनुरूप SIP स्टेटस टेक्स्ट                                                         |

**Twilio मेटाडेटा** (`type: "twilio"`):

| फ़ील्ड | टाइप   | ज़रूरी | विवरण                                                                                                                                    |
| ------ | ------ | ------ | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `type` | string | हाँ    | प्रोवाइडर प्रकार (हमेशा `twilio`)                                                                                                        |
| `body` | object | हाँ    | कॉल विवरण वाला Twilio StatusCallback बॉडी, जिसका दस्तावेज़ [यहाँ](https://www.twilio.com/docs/voice/api/call-resource#statuscallback) है |

## उदाहरण वेबहुक पेलोड

### ट्रांसक्रिप्शन वेबहुक उदाहरण

```json
{
  "type": "post_call_transcription",
  "event_timestamp": 1739537297,
  "data": {
    "agent_id": "xyz",
    "conversation_id": "abc",
    "status": "done",
    "user_id": "user123",
    "transcript": [
      {
        "role": "agent",
        "message": "Hey there angelo. How are you?",
        "tool_calls": null,
        "tool_results": null,
        "feedback": null,
        "time_in_call_secs": 0,
        "conversation_turn_metrics": null
      },
      {
        "role": "user",
        "message": "Hey, can you tell me, like, a fun fact about 11 Labs?",
        "tool_calls": null,
        "tool_results": null,
        "feedback": null,
        "time_in_call_secs": 2,
        "conversation_turn_metrics": null
      },
      {
        "role": "agent",
        "message": "I do not have access to fun facts about Eleven Labs. However, I can share some general information about the company. Eleven Labs is an AI voice technology platform that specializes in voice cloning and text-to-speech...",
        "tool_calls": null,
        "tool_results": null,
        "feedback": null,
        "time_in_call_secs": 9,
        "conversation_turn_metrics": {
          "convai_llm_service_ttfb": {
            "elapsed_time": 0.3704247010173276
          },
          "convai_llm_service_ttf_sentence": {
            "elapsed_time": 0.5551181449554861
          }
        }
      }
    ],
    "metadata": {
      "start_time_unix_secs": 1739537297,
      "call_duration_secs": 22,
      "cost": 296,
      "deletion_settings": {
        "deletion_time_unix_secs": 1802609320,
        "deleted_logs_at_time_unix_secs": null,
        "deleted_audio_at_time_unix_secs": null,
        "deleted_transcript_at_time_unix_secs": null,
        "delete_transcript_and_pii": true,
        "delete_audio": true
      },
      "feedback": {
        "overall_score": null,
        "likes": 0,
        "dislikes": 0
      },
      "authorization_method": "authorization_header",
      "charging": {
        "dev_discount": true
      },
      "termination_reason": ""
    },
    "analysis": {
      "evaluation_criteria_results": {},
      "data_collection_results": {},
      "call_successful": "success",
      "transcript_summary": "The conversation begins with the agent asking how Angelo is, but Angelo redirects the conversation by requesting a fun fact about 11 Labs. The agent acknowledges they don't have specific fun facts about Eleven Labs but offers to provide general information about the company. They briefly describe Eleven Labs as an AI voice technology platform specializing in voice cloning and text-to-speech technology. The conversation is brief and informational, with the agent adapting to the user's request despite not having the exact information asked for."
    },
    "conversation_initiation_client_data": {
      "conversation_config_override": {
        "agent": {
          "prompt": null,
          "first_message": null,
          "language": "en"
        },
        "tts": {
          "voice_id": null
        }
      },
      "custom_llm_extra_body": {},
      "dynamic_variables": {
        "user_name": "angelo"
      },
      "branch_id": null,
      "environment": null
    }
  }
}
```

### ऑडियो वेबहुक उदाहरण

```json
{
  "type": "post_call_audio",
  "event_timestamp": 1739537319,
  "data": {
    "agent_id": "xyz",
    "conversation_id": "abc",
    "full_audio": "SUQzBAAAAAAA...base64_encoded_mp3_data...AAAAAAAAAA=="
  }
}
```

### कॉल शुरू करने में विफलता के वेबहुक उदाहरण

#### Twilio मेटाडेटा उदाहरण

```json
{
  "type": "call_initiation_failure",
  "event_timestamp": 1759931652,
  "data": {
    "agent_id": "xyz",
    "conversation_id": "abc",
    "failure_reason": "busy",
    "metadata": {
      "type": "twilio",
      "body": {
        "Called": "+441111111111",
        "ToState": "",
        "CallerCountry": "US",
        "Direction": "outbound-api",
        "Timestamp": "Wed, 08 Oct 2025 13:54:12 +0000",
        "CallbackSource": "call-progress-events",
        "SipResponseCode": "487",
        "CallerState": "WA",
        "ToZip": "",
        "SequenceNumber": "2",
        "CallSid": "CA8367245817625617832576245724",
        "To": "+441111111111",
        "CallerZip": "98631",
        "ToCountry": "GB",
        "CalledZip": "",
        "ApiVersion": "2010-04-01",
        "CalledCity": "",
        "CallStatus": "busy",
        "Duration": "0",
        "From": "+11111111111",
        "CallDuration": "0",
        "AccountSid": "AC37682153267845716245762454a",
        "CalledCountry": "GB",
        "CallerCity": "RAYMOND",
        "ToCity": "",
        "FromCountry": "US",
        "Caller": "+11111111111",
        "FromCity": "RAYMOND",
        "CalledState": "",
        "FromZip": "12345",
        "FromState": "WA"
      }
    }
  }
}
```

#### SIP मेटाडेटा उदाहरण

```json
{
  "type": "call_initiation_failure",
  "event_timestamp": 1759931652,
  "data": {
    "agent_id": "xyz",
    "conversation_id": "abc",
    "failure_reason": "busy",
    "metadata": {
      "type": "sip",
      "body": {
        "from_number": "+441111111111",
        "to_number": "+11111111111",
        "sip_status_code": 486,
        "error_reason": "INVITE failed: sip status: 486: Busy here (SIP 486)",
        "call_sid": "d8e7f6a5-b4c3-4d5e-8f9a-0b1c2d3e4f5a",
        "sip_status": "Busy here",
        "twirp_code": "unavailable"
      }
    }
  }
}
```

## ऑडियो वेबहुक डिलीवरी

ऑडियो वेबहुक ट्रांसक्रिप्शन वेबहुक से अलग डिलीवर होते हैं और इनमें बातचीत की पहचान के लिए ज़रूरी फ़ील्ड के साथ सिर्फ़ base64-एन्कोडेड ऑडियो डेटा होता है।

> **Note**
>
> ऑडियो वेबहुक को आपकी वेबहुक सेटिंग्स में "ऑडियो डेटा भेजें" टॉगल से सक्षम या अक्षम किया जा सकता है। इस सेटिंग को वर्कस्पेस स्तर (ElevenAgents सेटिंग्स में)
> और एजेंट स्तर (अलग-अलग एजेंट वेबहुक ओवरराइड में) दोनों पर कॉन्फ़िगर किया जा सकता है।

### स्ट्रीमिंग डिलीवरी

बड़ी ऑडियो फ़ाइलों को कुशलता से संभालने के लिए ऑडियो वेबहुक `transfer-encoding: chunked` हेडर के साथ स्ट्रीमिंग HTTP अनुरोध के रूप में डिलीवर किए जाते हैं। हर अनुरोध 5 मिनट बाद टाइम आउट हो जाता है।

### रीट्राई

वेबहुक पर रीट्राई सक्षम होने पर, विफल ऑडियो डिलीवरी को ट्रांसक्रिप्शन वेबहुक के समान शेड्यूल पर फिर से आज़माया जाता है। रीट्राई पूरा ऑडियो पेलोड फिर से भेजती है, इसलिए `conversation_id` के आधार पर डुप्लिकेट हटाएं। शेड्यूल, रीट्राई योग्य त्रुटियों और ऑडियो साइज़ सीमाओं के लिए [वेबहुक रीट्राई](/docs/hi/eleven-api/resources/webhooks#retries) देखें।

### ऑडियो वेबहुक प्रोसेस करना

ऑडियो वेबहुक चंक्ड ट्रांसफ़र एन्कोडिंग से डिलीवर होते हैं, इसलिए आपको स्ट्रीमिंग डेटा को सही तरीके से संभालना होगा:

```python

import base64
import json
from aiohttp import web

async def handle_webhook(request):

    # Check if this is a chunked/streaming request
    if request.headers.get("transfer-encoding", "").lower() == "chunked":
        # Read streaming data in chunks
        chunked_body = bytearray()
        while True:
            chunk = await request.content.read(8192)  # 8KB chunks
            if not chunk:
                break
            chunked_body.extend(chunk)

        # Parse the complete payload
        request_body = json.loads(chunked_body.decode("utf-8"))
    else:
        # Handle regular requests
        body_bytes = await request.read()
        request_body = json.loads(body_bytes.decode('utf-8'))

    # Process different webhook types
    if request_body["type"] == "post_call_transcription":
        # Handle transcription webhook with full conversation data
        handle_transcription_webhook(request_body["data"])
    elif request_body["type"] == "post_call_audio":
        # Handle audio webhook with minimal data
        handle_audio_webhook(request_body["data"])
    elif request_body["type"] == "call_initiation_failure":
        # Handle call initiation failure webhook
        handle_call_initiation_failure_webhook(request_body["data"])

    return web.json_response({"status": "ok"})

def handle_audio_webhook(data):
    # Decode base64 audio data
    audio_bytes = base64.b64decode(data["full_audio"])

    # Save or process the audio file
    conversation_id = data["conversation_id"]
    with open(f"conversation_{conversation_id}.mp3", "wb") as f:
        f.write(audio_bytes)

def handle_call_initiation_failure_webhook(data):
    # Handle call initiation failure events
    agent_id = data["agent_id"]
    conversation_id = data["conversation_id"]
    failure_reason = data.get("failure_reason")
    metadata = data.get("metadata", {})

    # Log the failure for monitoring
    print(f"Call failed for agent {agent_id}, conversation {conversation_id}")
    print(f"Failure reason: {failure_reason}")

    # Access provider-specific metadata
    provider_type = metadata.get("type")
    body = metadata.get("body", {})
    if provider_type == "sip":
        print(f"SIP status code: {body.get('sip_status_code')}")
        print(f"Error reason: {body.get('error_reason')}")
    elif provider_type == "twilio":
        print(f"Twilio CallSid: {body.get('CallSid')}")
        print(f"Call status: {body.get('CallStatus')}")

    # Update your system with the failure information
    # e.g., mark lead as "call_failed" in CRM

```

```javascript
import fs from "fs";

app.post("/webhook/elevenlabs", (req, res) => {
  let body = "";

  // Handle chunked/streaming requests
  req.on("data", (chunk) => {
    body += chunk;
  });

  req.on("end", () => {
    try {
      const requestBody = JSON.parse(body);

      // Process different webhook types
      if (requestBody.type === "post_call_transcription") {
        // Handle transcription webhook with full conversation data
        handleTranscriptionWebhook(requestBody.data);
      } else if (requestBody.type === "post_call_audio") {
        // Handle audio webhook with minimal data
        handleAudioWebhook(requestBody.data);
      } else if (requestBody.type === "call_initiation_failure") {
        // Handle call initiation failure webhook
        handleCallFailureWebhook(requestBody.data);
      }

      res.status(200).json({ status: "ok" });
    } catch (error) {
      console.error("Error processing webhook:", error);
      res.status(400).json({ error: "Invalid JSON" });
    }
  });
});

function handleAudioWebhook(data) {
  // Decode base64 audio data
  const audioBytes = Buffer.from(data.full_audio, "base64");

  // Save or process the audio file
  const conversationId = data.conversation_id;
  fs.writeFileSync(`conversation_${conversationId}.mp3`, audioBytes);
}

function handleCallFailureWebhook(data) {
  // Handle call initiation failure events
  const { agent_id, conversation_id, failure_reason, metadata } = data;

  // Log the failure for monitoring
  console.log(`Call failed for agent ${agent_id}, conversation ${conversation_id}`);
  console.log(`Failure reason: ${failure_reason}`);

  // Access provider-specific metadata
  const body = metadata.body || {};
  if (metadata?.type === "sip") {
    console.log(`SIP status code: ${body.sip_status_code}`);
    console.log(`Error reason: ${body.error_reason}`);
  } else if (metadata?.type === "twilio") {
    console.log(`Twilio CallSid: ${body.CallSid}`);
    console.log(`Call status: ${body.CallStatus}`);
  }

  // Update your system with the failure information
  // e.g., mark lead as "call_failed" in CRM
}
```

> **Note**
>
> ऑडियो वेबहुक बड़ी फ़ाइलें हो सकती हैं, इसलिए सुनिश्चित करें कि आपका वेबहुक एंडपॉइंट स्ट्रीमिंग अनुरोधों को संभाल सकता है
> और उसके पास पर्याप्त मेमोरी/स्टोरेज क्षमता है। ऑडियो MP3 फ़ॉर्मैट में डिलीवर होता है।

## इस्तेमाल के मामले

### ऑटोमेटेड कॉल फ़ॉलो-अप

कॉल के बाद के वेबहुक आपको ऐसी ऑटोमेटेड वर्कफ़्लो बनाने देते हैं, जो कॉल खत्म होते ही ट्रिगर होते हैं। यहां कुछ व्यावहारिक उपयोग दिए गए हैं:

#### CRM इंटीग्रेशन

कॉल पूरी होते ही अपने कस्टमर रिलेशनशिप मैनेजमेंट सिस्टम को बातचीत के डेटा से अपडेट करें:

```javascript
// Example webhook handler
app.post("/webhook/elevenlabs", async (req, res) => {
  // HMAC validation code

  const { data } = req.body;

  // Extract key information
  const userId = data.metadata.user_id;
  const transcriptSummary = data.analysis.transcript_summary;
  const callSuccessful = data.analysis.call_successful;

  // Update CRM record
  await updateCustomerRecord(userId, {
    lastInteraction: new Date(),
    conversationSummary: transcriptSummary,
    callOutcome: callSuccessful,
    fullTranscript: data.transcript,
  });

  res.status(200).send("Webhook received");
});
```

### स्टेटफुल बातचीत

स्टेट स्टोर और रिट्रीव करके कई इंटरैक्शन में बातचीत का कॉन्टेक्स्ट बनाए रखें:

1. कॉल शुरू होने पर, अपना यूज़र ID एक डायनामिक वेरिएबल के रूप में पास करें।
2. कॉल खत्म होने पर, `dynamic_variables` से निकाली गई यूज़र ID के आधार पर अपनी वेबहुक एंडपॉइंट को अपने डेटाबेस में बातचीत का डेटा स्टोर करने के लिए सेट अप करें।
3. यूज़र के फिर से कॉल करने पर, आप इस कॉन्टेक्स्ट को रिट्रीव करके उसे नई बातचीत में \{\{previous_topics}} डायनामिक वेरिएबल में पास कर सकते हैं।
4. इससे एक सहज अनुभव बनता है, जिसमें एजेंट पिछले इंटरैक्शन को "याद" रखता है

```javascript
// Store conversation state when call ends
app.post("/webhook/elevenlabs", async (req, res) => {
  // HMAC validation code

  const { data } = req.body;
  const userId = data.metadata.user_id;

  // Store conversation state
  await db.userStates.upsert({
    userId,
    lastConversationId: data.conversation_id,
    lastInteractionTimestamp: data.metadata.start_time_unix_secs,
    conversationHistory: data.transcript,
    previousTopics: extractTopics(data.analysis.transcript_summary),
  });

  res.status(200).send("Webhook received");
});

// When initiating a new call, retrieve and use the state
async function initiateCall(userId) {
  // Get user's conversation state
  const userState = await db.userStates.findOne({ userId });

  // Start new conversation with context from previous calls
  return await elevenlabs.startConversation({
    agent_id: "xyz",
    conversation_id: generateNewId(),
    dynamic_variables: {
      user_name: userState.name,
      previous_conversation_id: userState.lastConversationId,
      previous_topics: userState.previousTopics.join(", "),
    },
  });
}
```