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

# Webhooks

> ElevenLabs incoming webhooks: event paths, payloads, and response data.

The ElevenLabs plugin handles incoming webhooks. In ElevenLabs, create a webhook under Developers, Webhooks with HMAC auth, point it at your Corsair HTTP handler, and save the secret it shows you as the account's `webhook_signature` (see [Overview](https://docs.corsair.dev/plugins/elevenlabs/overview.md) for setup). Tick the events you want; post-call events also need the webhook selected in the agent's settings. Deliveries name no account, so with several tenants add `?tenantId=<id>` to the URL. The signature covers the body but not the URL, so `?tenantId=` only picks which tenant's secret checks a delivery. When tenants share a secret, by storing the same one or through the `webhookSecret` option, anyone holding a signed delivery under 30 minutes old can resend it with another `tenantId`, and that tenant's hooks run on it. Give each tenant its own webhook secret, or check in an `after` hook that the event's ids belong to that tenant before acting on it. By then the plugin has logged the event under that tenant. A `before` hook runs ahead of the signature check, so it can receive an unsigned or forged delivery. Keep side effects in `after`. The same event can arrive more than once, from ElevenLabs' retries or from someone resending a signed delivery within 30 minutes, so make hooks safe to run twice, for example by recording the `conversation_id` or `request_id` each one acted on.

> [!NOTE]
>
> **New to Corsair?** See [webhooks](https://docs.corsair.dev/concepts/webhooks.md) and [hooks](https://docs.corsair.dev/concepts/hooks.md).

## Webhook map

* `conversations`
  * `callInitiationFailure` (`conversations.callInitiationFailure`)
  * `postCallAudio` (`conversations.postCallAudio`)
  * `postCallTranscription` (`conversations.postCallTranscription`)
* `speechToText`
  * `transcriptionCompleted` (`speechToText.transcriptionCompleted`)
  * `transcriptionFailed` (`speechToText.transcriptionFailed`)
* `voices`
  * `removalNotice` (`voices.removalNotice`)
  * `removalNoticeWithdrawn` (`voices.removalNoticeWithdrawn`)
  * `removed` (`voices.removed`)

## HTTP handler setup

```ts app/api/webhook/route.ts theme={null}
import { processWebhook } from "corsair";
import { corsair } from "@/server/corsair";

export async function POST(request: Request) {
    const headers = Object.fromEntries(request.headers);
    // The raw text: ElevenLabs signs the exact bytes it sent, so don't parse it first.
    const body = await request.text();
    // Carries ?tenantId=<id>, which picks the tenant whose secret checks the signature.
    const query = Object.fromEntries(new URL(request.url).searchParams);
    const result = await processWebhook(corsair, headers, body, query);
    // Answer non-2xx when processing failed (a bad signature, a payload that fails
    // validation, no secret stored yet), so ElevenLabs counts it and retries if retries are on.
    return Response.json(result.response ?? { success: false }, {
        status: !result.plugin ? 404 : result.response?.success === false ? 500 : 200,
    });
}
```

## Events

## Conversations

### Call Initiation Failure

`conversations.callInitiationFailure`

A phone call could not be started: busy, no answer or unknown.

**Payload**

| Name | Type | Required | Description |
| - | - | - | - |
| `type` | `call_initiation_failure` | Yes | — |
| `event_timestamp` | `number \| string \| null` | No | When the event happened, in Unix time. |
| `data` | `object \| null` | No | — |

> [accordion] data full type
>
> ```ts theme={null}
> {
>   agent_id?: string | null,
>   conversation_id?: string | null,
>   failure_reason?: string | null,
>   metadata?: Record<string, any> | null
> } | null
> ```

> [accordion] Response data full type
>
> ```ts theme={null}
> {
>   type: call_initiation_failure,
>   event_timestamp?: number | string | null,
>   data?: {
>     agent_id?: string | null,
>     conversation_id?: string | null,
>     failure_reason?: string | null,
>     metadata?: Record<string, any> | null
>   } | null
> }
> ```

**`webhookHooks` example**

```ts theme={null}
elevenlabs({
    webhookHooks: {
        conversations: {
            callInitiationFailure: {
                before(ctx, args) {
                    return { ctx, args };
                },
                after(ctx, response) {
                },
            },
        },
    },
})
```

***

### Post Call Audio

`conversations.postCallAudio`

A conversation ended: the whole conversation as base64 MP3.

**Payload**

| Name | Type | Required | Description |
| - | - | - | - |
| `type` | `post_call_audio` | Yes | — |
| `event_timestamp` | `number \| string \| null` | No | When the event happened, in Unix time. |
| `data` | `object \| null` | No | — |

> [accordion] data full type
>
> ```ts theme={null}
> {
>   agent_id?: string | null,
>   conversation_id?: string | null,
>   full_audio?: string | null
> } | null
> ```

> [accordion] Response data full type
>
> ```ts theme={null}
> {
>   type: post_call_audio,
>   event_timestamp?: number | string | null,
>   data?: {
>     agent_id?: string | null,
>     conversation_id?: string | null,
>     full_audio?: string | null
>   } | null
> }
> ```

**`webhookHooks` example**

```ts theme={null}
elevenlabs({
    webhookHooks: {
        conversations: {
            postCallAudio: {
                before(ctx, args) {
                    return { ctx, args };
                },
                after(ctx, response) {
                },
            },
        },
    },
})
```

***

### Post Call Transcription

`conversations.postCallTranscription`

A conversation ended and its analysis is ready: transcript, metadata and analysis.

**Payload**

| Name | Type | Required | Description |
| - | - | - | - |
| `type` | `post_call_transcription` | Yes | — |
| `event_timestamp` | `number \| string \| null` | No | When the event happened, in Unix time. |
| `data` | `object \| null` | No | — |

> [accordion] data full type
>
> ```ts theme={null}
> {
>   agent_id?: string | null,
>   conversation_id?: string | null,
>   status?: string | null,
>   transcript?: Record<string, any>[] | null,
>   metadata?: Record<string, any> | null,
>   analysis?: Record<string, any> | null
> } | null
> ```

> [accordion] Response data full type
>
> ```ts theme={null}
> {
>   type: post_call_transcription,
>   event_timestamp?: number | string | null,
>   data?: {
>     agent_id?: string | null,
>     conversation_id?: string | null,
>     status?: string | null,
>     transcript?: Record<string, any>[] | null,
>     metadata?: Record<string, any> | null,
>     analysis?: Record<string, any> | null
>   } | null
> }
> ```

**`webhookHooks` example**

```ts theme={null}
elevenlabs({
    webhookHooks: {
        conversations: {
            postCallTranscription: {
                before(ctx, args) {
                    return { ctx, args };
                },
                after(ctx, response) {
                },
            },
        },
    },
})
```

***

## Speech To Text

### Transcription Completed

`speechToText.transcriptionCompleted`

A transcription started with webhook true finished.

**Payload**

| Name | Type | Required | Description |
| - | - | - | - |
| `type` | `speech_to_text_transcription` | Yes | — |
| `event_timestamp` | `number \| string \| null` | No | When the event happened, in Unix time. |
| `data` | `object \| null` | No | — |

> [accordion] data full type
>
> ```ts theme={null}
> {
>   request_id?: string | null,
>   webhook_metadata?: Record<string, any> | string | null,
>   transcription?: {
>     language_code?: string | null,
>     language_probability?: number | null,
>     text?: string | null,
>     words?: Record<string, any>[] | null,
>     transcription_id?: string | null
>   } | null
> } | null
> ```

> [accordion] Response data full type
>
> ```ts theme={null}
> {
>   type: speech_to_text_transcription,
>   event_timestamp?: number | string | null,
>   data?: {
>     request_id?: string | null,
>     webhook_metadata?: Record<string, any> | string | null,
>     transcription?: {
>       language_code?: string | null,
>       language_probability?: number | null,
>       text?: string | null,
>       words?: Record<string, any>[] | null,
>       transcription_id?: string | null
>     } | null
>   } | null
> }
> ```

**`webhookHooks` example**

```ts theme={null}
elevenlabs({
    webhookHooks: {
        speechToText: {
            transcriptionCompleted: {
                before(ctx, args) {
                    return { ctx, args };
                },
                after(ctx, response) {
                },
            },
        },
    },
})
```

***

### Transcription Failed

`speechToText.transcriptionFailed`

A transcription started with webhook true failed.

**Payload**

| Name | Type | Required | Description |
| - | - | - | - |
| `type` | `webhook_error` | Yes | — |
| `event_timestamp` | `number \| string \| null` | No | When the event happened, in Unix time. |
| `request_id` | `string \| null` | No | The request\_id speechToText.convert returned. |
| `error_message` | `string \| null` | No | — |
| `webhook_metadata` | `Record<string, any> \| string \| null` | No | — |

> [accordion] Response data full type
>
> ```ts theme={null}
> {
>   type: webhook_error,
>   event_timestamp?: number | string | null,
>   request_id?: string | null,
>   error_message?: string | null,
>   webhook_metadata?: Record<string, any> | string | null
> }
> ```

**`webhookHooks` example**

```ts theme={null}
elevenlabs({
    webhookHooks: {
        speechToText: {
            transcriptionFailed: {
                before(ctx, args) {
                    return { ctx, args };
                },
                after(ctx, response) {
                },
            },
        },
    },
})
```

***

## Voices

### Removal Notice

`voices.removalNotice`

A shared voice in use is scheduled to be removed.

**Payload**

| Name | Type | Required | Description |
| - | - | - | - |
| `type` | `voice_removal_notice` | Yes | — |
| `event_timestamp` | `number \| string \| null` | No | When the event happened, in Unix time. |
| `data` | `Record<string, any> \| null` | No | — |

> [accordion] Response data full type
>
> ```ts theme={null}
> {
>   type: voice_removal_notice,
>   event_timestamp?: number | string | null,
>   data?: Record<string, any> | null
> }
> ```

**`webhookHooks` example**

```ts theme={null}
elevenlabs({
    webhookHooks: {
        voices: {
            removalNotice: {
                before(ctx, args) {
                    return { ctx, args };
                },
                after(ctx, response) {
                },
            },
        },
    },
})
```

***

### Removal Notice Withdrawn

`voices.removalNoticeWithdrawn`

A shared voice is no longer scheduled for removal.

**Payload**

| Name | Type | Required | Description |
| - | - | - | - |
| `type` | `voice_removal_notice_withdrawn` | Yes | — |
| `event_timestamp` | `number \| string \| null` | No | When the event happened, in Unix time. |
| `data` | `Record<string, any> \| null` | No | — |

> [accordion] Response data full type
>
> ```ts theme={null}
> {
>   type: voice_removal_notice_withdrawn,
>   event_timestamp?: number | string | null,
>   data?: Record<string, any> | null
> }
> ```

**`webhookHooks` example**

```ts theme={null}
elevenlabs({
    webhookHooks: {
        voices: {
            removalNoticeWithdrawn: {
                before(ctx, args) {
                    return { ctx, args };
                },
                after(ctx, response) {
                },
            },
        },
    },
})
```

***

### Removed

`voices.removed`

A shared voice was removed and can no longer be used.

**Payload**

| Name | Type | Required | Description |
| - | - | - | - |
| `type` | `voice_removed` | Yes | — |
| `event_timestamp` | `number \| string \| null` | No | When the event happened, in Unix time. |
| `data` | `Record<string, any> \| null` | No | — |

> [accordion] Response data full type
>
> ```ts theme={null}
> {
>   type: voice_removed,
>   event_timestamp?: number | string | null,
>   data?: Record<string, any> | null
> }
> ```

**`webhookHooks` example**

```ts theme={null}
elevenlabs({
    webhookHooks: {
        voices: {
            removed: {
                before(ctx, args) {
                    return { ctx, args };
                },
                after(ctx, response) {
                },
            },
        },
    },
})
```

***


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.