Asynchronous Speech to Text

Learn how to use webhooks to receive asynchronous notifications when your transcription tasks are completed.

Overview

Webhooks allow you to receive automatic notifications when your Speech to Text transcription tasks are completed, eliminating the need to continuously poll the API for status updates. This is particularly useful for long-running transcription jobs or when processing large volumes of audio files.

When a transcription is completed, ElevenLabs will send a POST request to your specified webhook URL with the transcription results, including the transcript text, language detection, and any metadata.

Using webhooks

1

Create a webhook endpoint

First, create a webhook in the ElevenLabs dashboard. Navigate to your webhooks settings and click “Create Webhook”.

Create webhook interface
Create a new webhook in the ElevenLabs dashboard

Configure your webhook with:

  • Name: A descriptive name for your webhook
  • Callback URL: Your publicly accessible HTTPS endpoint
  • Webhook Auth Method: Either HMAC or OAuth. It is up to the client to implement the verification mechanism. ElevenLabs sends headers that allow for verification but we do not enforce it.
2

Associate webhook with transcription tasks

Once created, you can associate the webhook with your speech-to-text tasks. In the dashboard, navigate to the webhook events section and link your webhooks to speech-to-text events.

Webhook association interface
Associate webhook with speech-to-text tasks
3

Create an API key

Create an API key in the dashboard here, which you’ll use to securely access the API.

Store the key as a managed secret and pass it to the SDKs either as a environment variable via an .env file, or directly in your app’s configuration depending on your preference.

.env
1ELEVENLABS_API_KEY=<your_api_key_here>
4

Install the SDK

We’ll also use the dotenv library to load our API key from an environment variable.

1pip install elevenlabs
2pip install python-dotenv
5

Make API calls with webhook parameter enabled

When making speech-to-text API calls, include the webhook parameter set to true to enable webhook notifications for that specific request.

1from dotenv import load_dotenv
2from elevenlabs.client import ElevenLabs
3
4load_dotenv()
5
6elevenlabs = ElevenLabs(
7 api_key=os.getenv("ELEVENLABS_API_KEY"),
8)
9
10def transcribe_with_webhook(audio_file):
11 try:
12 result = elevenlabs.speech_to_text.convert(
13 file=audio_file,
14 model_id="scribe_v1",
15 webhook=True,
16 )
17 print(f"Transcription started: {result.task_id}")
18 return result
19 except Exception as e:
20 print(f"Error starting transcription: {e}")
21 raise e

Webhook payload

When a transcription is completed, your webhook endpoint will receive a POST request with the identical payload as the non-webhook API:

1{
2 "language_code": "en",
3 "language_probability": 0.98,
4 "text": "Hello world!",
5 "words": [
6 {
7 "text": "Hello",
8 "start": 0.0,
9 "end": 0.5,
10 "type": "word",
11 "speaker_id": "speaker_1"
12 },
13 {
14 "text": " ",
15 "start": 0.5,
16 "end": 0.5,
17 "type": "spacing",
18 "speaker_id": "speaker_1"
19 },
20 {
21 "text": "world!",
22 "start": 0.5,
23 "end": 1.2,
24 "type": "word",
25 "speaker_id": "speaker_1"
26 }
27 ]
28}

Please refer to the Speech-to-text API reference to learn about the details of the response structure.

Implementing your webhook endpoint

Here’s an example of how to implement a webhook endpoint to handle incoming notifications:

1import { ElevenLabsClient } from '@elevenlabs/elevenlabs-js';
2import 'dotenv/config';
3import express from 'express';
4
5const elevenlabs = new ElevenLabsClient();
6
7const app = express();
8app.use(express.json());
9
10const WEBHOOK_SECRET = process.env.WEBHOOK_SECRET;
11
12app.post('/webhook/speech-to-text', (req, res) => {
13 try {
14 const signature = req.headers['x-elevenlabs-signature'];
15 const payload = JSON.stringify(req.body);
16 let event;
17
18 try {
19 // Verify the webhook signature.
20 event = elevenlabs.webhooks.constructEvent(payload, signature, WEBHOOK_SECRET);
21 } catch (error) {
22 return res.status(401).json({ error: 'Invalid signature' });
23 }
24
25 if (event.type === 'speech_to_text.completed') {
26 const { task_id, status, text, language_code } = event.data;
27
28 console.log(`Transcription ${task_id} completed`);
29 console.log(`Language: ${language_code}`);
30 console.log(`Text: ${text}`);
31
32 processTranscription(task_id, text, language_code);
33 } else if (status === 'failed') {
34 console.error(`Transcription ${task_id} failed`);
35 handleTranscriptionError(task_id);
36 }
37
38 res.status(200).json({ received: true });
39 } catch (error) {
40 console.error('Webhook error:', error);
41 res.status(500).json({ error: 'Internal server error' });
42 }
43});
44
45async function processTranscription(taskId, text, language) {
46 console.log('Processing completed transcription...');
47}
48
49async function handleTranscriptionError(taskId) {
50 console.log('Handling transcription error...');
51}
52
53app.listen(3000, () => {
54 console.log('Webhook server listening on port 3000');
55});

Security considerations

Signature verification

Always verify webhook signatures to ensure requests came from ElevenLabs.

HTTPS requirement

Webhook URLs must use HTTPS to ensure secure transmission of transcription data.

Rate limiting

Implement rate limiting on your webhook endpoint to prevent abuse:

1import rateLimit from 'express-rate-limit';
2
3const webhookLimiter = rateLimit({
4 windowMs: 15 * 60 * 1000, // 15 minutes
5 max: 100, // limit each IP to 100 requests per windowMs
6 message: 'Too many webhook requests from this IP',
7});
8
9app.use('/webhook', webhookLimiter);

Failure responses

Return appropriate HTTP status codes:

  • 200-299: Success - webhook processed successfully
  • 400-499: Client error - webhook will not be retried
  • 500-599: Server error - webhook will be retried

Testing webhooks

Local development

For local testing, use tools like ngrok to expose your local server:

$ngrok http 3000

Use the provided HTTPS URL as your webhook endpoint during development.

Webhook testing

You can test your webhook implementation by making a transcription request and monitoring your endpoint:

1async function testWebhook() {
2 const audioFile = new File([audioBuffer], 'test.mp3', { type: 'audio/mp3' });
3
4 const result = await elevenlabs.speechToText.convert({
5 file: audioFile,
6 modelId: 'scribe_v1',
7 webhook: true,
8 });
9
10 console.log('Test transcription started:', result.task_id);
11}