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

# Webhooks for pre-recorded audio

Webhooks are custom HTTP callbacks that you can define to get notified when your pre-recorded audio transcripts are ready.

> [!NOTE]
>
> This guide covers webhooks for [pre-recorded audio
> transcription](https://assemblyai.com/docs/pre-recorded-audio). For webhooks with
> streaming audio, see [Webhooks for streaming
> speech-to-text](https://assemblyai.com/docs/streaming/webhooks.md).

To use webhooks, you need to set up your own webhook receiver to handle webhook deliveries.

## Create a webhook for a transcription

> [!TIP]
>
> **Don't have a webhook endpoint yet?**
>
> Create a test webhook endpoint with [webhook.site](https://webhook.site) to
> test your webhook integration.

> [tab] Python
>
> To create a webhook, set the `webhook_url` parameter when you create a new transcription. The URL must be accessible from AssemblyAI's servers.
>
> ```python expandable theme={null}
> import requests
> import time
>
> base_url = "https://api.assemblyai.com"
>
> headers = {
>     "authorization": "<YOUR_API_KEY>"
> }
>
> with open("./my-audio.mp3", "rb") as f:
>   response = requests.post(base_url + "/v2/upload",
>                           headers=headers,
>                           data=f)
>
> upload_url = response.json()["upload_url"]
>
> data = {
>     "audio_url": upload_url,
>     "webhook_url": "https://example.com/webhook"
> }
>
> url = base_url + "/v2/transcript"
> response = requests.post(url, json=data, headers=headers)
> ```

> [tab] Python SDK
>
> To create a webhook, use `set_webhook()` on the transcription config. The URL must be accessible from AssemblyAI's servers.
>
> Use `submit()` instead of `transcribe()` to create a transcription without waiting for it to complete.
>
> ```python theme={null}
> from assemblyai.prerecorded.v2 import Transcriber, TranscriptionConfig
>
> # audio_file = "./local_file.mp3"
> audio_file = "https://assembly.ai/wildfires.mp3"
>
> config = TranscriptionConfig().set_webhook("https://example.com/webhook")
>
> transcriber = Transcriber(api_key="<YOUR_API_KEY>")
> transcriber.submit(audio_file, config)
> ```

> [tab] JavaScript
>
> To create a webhook, set the `webhook_url` parameter when you create a new transcription. The URL must be accessible from AssemblyAI's servers.
>
> ```javascript expandable theme={null}
> import fs from "fs-extra";
>
> const baseUrl = "https://api.assemblyai.com";
>
> const headers = {
>   authorization: "<YOUR_API_KEY>",
> };
>
> const path = "./my-audio.mp3";
> const audioData = await fs.readFile(path);
> let res = await fetch(`${baseUrl}/v2/upload`, {
>   method: "POST",
>   headers,
>   body: audioData,
> });
> if (!res.ok) throw new Error(`Error: ${res.status}`);
> const uploadResponse = await res.json();
> const uploadUrl = uploadResponse.upload_url;
>
> const data = {
>   audio_url: uploadUrl,
>   webhook_url: "https://example.com/webhook",
> };
>
> const url = `${baseUrl}/v2/transcript`;
> const response = await fetch(url, {
>   method: "POST",
>   headers: { ...headers, "Content-Type": "application/json" },
>   body: JSON.stringify(data),
> });
> if (!response.ok) throw new Error(`Error: ${response.status}`);
> ```

> [tab] JavaScript SDK
>
> To create a webhook, include the `webhook_url` parameter when you create a new transcription. The URL must be accessible from AssemblyAI's servers.
>
> Use `submit()` instead of `transcribe()` to create a transcription without waiting for it to complete.
>
> ```javascript theme={null}
> import { AssemblyAI } from "assemblyai";
>
> const client = new AssemblyAI({
>   apiKey: "<YOUR_API_KEY>",
> });
>
> // const audioFile = './local_file.mp3'
> const audioFile = "https://assembly.ai/wildfires.mp3";
>
> const params = {
>   audio: audioFile,
>   webhook_url: "https://example.com/webhook",
> };
>
> const run = async () => {
>   const transcript = await client.transcripts.submit(params);
> };
>
> run();
> ```

## Handle webhook deliveries

When the transcript is ready, AssemblyAI will send a `POST` HTTP request to the URL that you specified.

Your webhook endpoint must return a 2xx HTTP status code within 10 seconds to indicate successful receipt. If a 2xx status is not received within 10 seconds, AssemblyAI will retry the webhook call up to a total of 10 attempts. If at any point your endpoint returns a 4xx status code, the webhook call is considered failed and will not be retried.

> [!NOTE]
>
> **Static Webhook IP addresses**
>
> AssemblyAI sends all webhook deliveries from fixed IP addresses:
>
> | Region | IP Address |
> | - | - |
> | US | `44.238.19.20` |
> | EU | `54.220.25.36` |

### Delivery payload

The webhook delivery payload contains a JSON object with the following properties:

```json theme={null}
{
  "transcript_id": "5552493-16d8-42d8-8feb-c2a16b56f6e8",
  "status": "completed"
}
```

| Key | Type | Description |
| - | - | - |
| `transcript_id` | string | The ID of the transcript. |
| `status` | string | The status of the transcript. Either `completed` or `error`. |

The webhook payload only contains the `transcript_id` and `status`. It doesn't include the transcript text or error details. If the `status` is `"error"`, make a `GET /v2/transcript/{transcript_id}` request to retrieve the error message from the `error` field in the response. See [Retrieve a transcript with the transcript ID](#retrieve-a-transcript-with-the-transcript-id) below.

### Webhook status code

When you retrieve the transcript using the transcript ID, the JSON response will include a `webhook_status_code` field. This field contains the HTTP status code that AssemblyAI received when calling your webhook endpoint, allowing you to verify that the webhook was delivered successfully.

### Retrieve a transcript with the transcript ID

> [tab] Python
>
> ```python theme={null}
> import requests
> import time
>
> base_url = "https://api.assemblyai.com"
>
> headers = {
>     "authorization": "<YOUR_API_KEY>"
> }
>
> transcript_id = "<TRANSCRIPT_ID>"
>
> polling_endpoint = f"https://api.assemblyai.com/v2/transcript/{transcript_id}"
>
> transcription_result = requests.get(polling_endpoint, headers=headers).json()
>
> if transcription_result['status'] == 'completed':
>   print(f"Transcript ID: {transcript_id}")
> elif transcription_result['status'] == 'error':
>   raise RuntimeError(f"Transcription failed: {transcription_result['error']}")
>
> ```

> [tab] Python SDK
>
> ```python theme={null}
> import assemblyai
> from assemblyai.prerecorded.v2 import Transcript
>
> # `Transcript.get_by_id()` uses the default client, which reads the global settings.
> assemblyai.settings.api_key = "<YOUR_API_KEY>"
>
> transcript = Transcript.get_by_id("<TRANSCRIPT_ID>")
>
> if transcript.status == "error":
>   raise RuntimeError(f"Transcription failed: {transcript.error}")
>
> print(transcript.text)
>
> ```

> [tab] JavaScript
>
> ```javascript theme={null}
> import fs from "fs-extra";
>
> const baseUrl = "https://api.assemblyai.com";
>
> const headers = {
>   authorization: "<YOUR_API_KEY>",
> };
>
> const transcriptId = "<TRANSCRIPT_ID>";
> const pollingEndpoint = `${baseUrl}/v2/transcript/${transcriptId}`;
>
> let res = await fetch(pollingEndpoint, { headers });
> if (!res.ok) throw new Error(`Error: ${res.status}`);
> const transcriptionResult = await res.json();
>
> if (transcriptionResult.status === "completed") {
>   console.log(transcriptionResult.text);
> } else if (transcriptionResult.status === "error") {
>   throw new Error(`Transcription failed: ${transcriptionResult.error}`);
> }
> ```

> [tab] JavaScript SDK
>
> ```javascript theme={null}
> import { AssemblyAI } from "assemblyai";
>
> const client = new AssemblyAI({
>   apiKey: "<YOUR_API_KEY>",
> });
>
> const transcript = await client.transcripts.get("<TRANSCRIPT_ID>");
>
> if (transcript.status === "error") {
>   throw new Error(`Transcription failed: ${transcript.error}`);
> }
>
> console.log(transcript.text);
> ```

## Authenticate webhook deliveries

You can authenticate webhook deliveries from AssemblyAI by including a custom HTTP header in the request.

> [tab] Python
>
> To add an authentication header, include the auth header name and value in `set_webhook()`.
>
> ```python {2} theme={null}
> config = TranscriptionConfig().set_webhook(
>     "https://example.com/webhook", "X-My-Webhook-Secret", "secret-value"
> )
>
> transcriber = Transcriber(api_key="<YOUR_API_KEY>")
> transcriber.submit(audio_url, config)
> ```

> [tab] JavaScript
>
> To add an authentication header, include the `webhook_auth_header_name` and `webhook_auth_header_value` parameters.
>
> ```javascript {5-6} theme={null}
> client.transcripts.submit({
>   audio:
>     'https://assembly.ai/wildfires.mp3',
>   webhook_url: 'https://example.com/webhook',
>   webhook_auth_header_name: "X-My-Webhook-Secret",
>   webhook_auth_header_value: "secret-value"
> })
> ```

> [tab] Python
>
> To add an authentication header, include the auth header name and value in `set_webhook()`.
>
> ```python expandable theme={null}
> import requests
> import time
>
> base_url = "https://api.assemblyai.com"
>
> headers = {
>     "authorization": "<YOUR_API_KEY>"
> }
>
> with open("./my-audio.mp3", "rb") as f:
>   response = requests.post(base_url + "/v2/upload",
>                           headers=headers,
>                           data=f)
>
> upload_url = response.json()["upload_url"]
>
> data = {
>     "audio_url": upload_url,
>     "webhook_url": "https://example.com/webhook",
>     "webhook_auth_header_name": "X-My-Webhook-Secret",
>     "webhook_auth_header_value": "secret-value"
> }
>
> url = base_url + "/v2/transcript"
> response = requests.post(url, json=data, headers=headers)
> ```

> [tab] Python SDK
>
> To add an authentication header, include the auth header name and value in `set_webhook()`.
>
> ```python theme={null}
> from assemblyai.prerecorded.v2 import Transcriber, TranscriptionConfig
>
> # audio_file = "./local_file.mp3"
> audio_file = "https://assembly.ai/wildfires.mp3"
>
> config = TranscriptionConfig().set_webhook("https://example.com/webhook", "X-My-Webhook-Secret", "secret-value")
>
> transcriber = Transcriber(api_key="<YOUR_API_KEY>")
> transcriber.submit(audio_file, config)
> ```

> [tab] JavaScript
>
> To add an authentication header, include the `webhook_auth_header_name` and `webhook_auth_header_value` parameters.
>
> ```javascript expandable theme={null}
> import fs from "fs-extra";
>
> const baseUrl = "https://api.assemblyai.com";
>
> const headers = {
>   authorization: "<YOUR_API_KEY>",
> };
>
> const path = "./my-audio.mp3";
> const audioData = await fs.readFile(path);
> let res = await fetch(`${baseUrl}/v2/upload`, {
>   method: "POST",
>   headers,
>   body: audioData,
> });
> if (!res.ok) throw new Error(`Error: ${res.status}`);
> const uploadResponse = await res.json();
> const uploadUrl = uploadResponse.upload_url;
>
> const data = {
>   audio_url: uploadUrl,
>   webhook_url: "https://example.com/webhook",
>   webhook_auth_header_name: "X-My-Webhook-Secret",
>   webhook_auth_header_value: "secret-value",
> };
>
> const url = `${baseUrl}/v2/transcript`;
> const response = await fetch(url, {
>   method: "POST",
>   headers: { ...headers, "Content-Type": "application/json" },
>   body: JSON.stringify(data),
> });
> if (!response.ok) throw new Error(`Error: ${response.status}`);
> ```

> [tab] JavaScript SDK
>
> To add an authentication header, include the `webhook_auth_header_name` and `webhook_auth_header_value` parameters.
>
> ```javascript expandable theme={null}
> import { AssemblyAI } from "assemblyai";
>
> const client = new AssemblyAI({
>   apiKey: "<YOUR_API_KEY>",
> });
>
> // const audioFile = './local_file.mp3'
> const audioFile = "https://assembly.ai/wildfires.mp3";
>
> const params = {
>   audio: audioFile,
>   webhook_url: "https://example.com/webhook",
>   webhook_auth_header_name: "X-My-Webhook-Secret",
>   webhook_auth_header_value: "secret-value",
> };
>
> const run = async () => {
>   const transcript = await client.transcripts.submit(params);
> };
>
> run();
> ```

## Add metadata to webhook deliveries

To associate metadata for a specific transcription request, you can add your own query parameters to the webhook URL.

```plain theme={null}
https://example.com/webhook?customer_id=1234&order_id=5678
```

Now, when you receive the webhook delivery, you'll know the customer who requested it.

## Failed webhook deliveries

Webhook deliveries can fail for multiple reasons. For example, if your server is down or takes more than 10 seconds to respond.

If a webhook delivery fails, AssemblyAI will attempt to redeliver it up to 10 times, waiting 10 seconds between each attempt. If all attempts fail, AssemblyAI considers the delivery as permanently failed.
