elevenlabs-webhooks-events
Implement ElevenLabs webhook HMAC signature verification and event handling. Use when setting up webhook endpoints for transcription completion, call recording, or agent conversation events from ElevenLabs. Trigger: "elevenlabs webhook", "elevenlabs events", "elevenlabs webhook signature", "handle elevenlabs notifications", "elevenlabs post-call webhook", "elevenlabs transcription webhook".
Best use case
elevenlabs-webhooks-events is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
Implement ElevenLabs webhook HMAC signature verification and event handling. Use when setting up webhook endpoints for transcription completion, call recording, or agent conversation events from ElevenLabs. Trigger: "elevenlabs webhook", "elevenlabs events", "elevenlabs webhook signature", "handle elevenlabs notifications", "elevenlabs post-call webhook", "elevenlabs transcription webhook".
Teams using elevenlabs-webhooks-events should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/elevenlabs-webhooks-events/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How elevenlabs-webhooks-events Compares
| Feature / Agent | elevenlabs-webhooks-events | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
Implement ElevenLabs webhook HMAC signature verification and event handling. Use when setting up webhook endpoints for transcription completion, call recording, or agent conversation events from ElevenLabs. Trigger: "elevenlabs webhook", "elevenlabs events", "elevenlabs webhook signature", "handle elevenlabs notifications", "elevenlabs post-call webhook", "elevenlabs transcription webhook".
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
SKILL.md Source
# ElevenLabs Webhooks & Events
## Overview
ElevenLabs webhooks send HTTP POST notifications when async operations complete. Supported event types include transcription completion, post-call data from Conversational AI agents, and call initiation failures. Webhooks use HMAC-SHA256 signatures for verification.
## Prerequisites
- ElevenLabs account (webhooks configured in Settings > Webhooks)
- HTTPS endpoint accessible from the internet
- Webhook secret (generated during webhook creation in dashboard)
## Instructions
### Step 1: Webhook Event Types
| Event Type | Payload | When Triggered |
|------------|---------|----------------|
| `post_call_transcription` | Full conversation transcript, analysis, metadata | After Conversational AI call ends |
| `post_call_audio` | Base64-encoded call audio, minimal metadata | After call ends (if audio recording enabled) |
| `call_initiation_failure` | Failure reason, metadata | When an outbound call fails to connect |
| `speech_to_text.completed` | Transcription result, word timestamps | Async STT job completes |
### Step 2: Webhook Setup
```bash
# Create webhook in ElevenLabs dashboard:
# Settings > Webhooks > Create Webhook
# - URL: https://your-app.com/webhooks/elevenlabs
# - Select event types to subscribe to
# - Copy the generated HMAC secret
```
### Step 3: HMAC Signature Verification
```typescript
// src/elevenlabs/webhook-verify.ts
import crypto from "crypto";
/**
* Verify the ElevenLabs-Signature header using HMAC-SHA256.
*
* Header format: t=<unix_timestamp>,v1=<hex_signature>
* Signed payload: "<timestamp>.<raw_body>"
*/
export function verifyWebhookSignature(
rawBody: string | Buffer,
signatureHeader: string,
secret: string
): { valid: boolean; reason?: string } {
if (!signatureHeader || !secret) {
return { valid: false, reason: "Missing signature header or secret" };
}
// Parse header: t=1234567890,v1=abcdef...
const parts = new Map(
signatureHeader.split(",").map(p => {
const [key, ...val] = p.split("=");
return [key, val.join("=")] as [string, string];
})
);
const timestamp = parts.get("t");
const signature = parts.get("v1");
if (!timestamp || !signature) {
return { valid: false, reason: "Malformed signature header" };
}
// Replay protection: reject if older than 5 minutes
const age = Math.floor(Date.now() / 1000) - parseInt(timestamp);
if (age > 300) {
return { valid: false, reason: `Timestamp too old: ${age}s` };
}
// Compute expected HMAC
const signedPayload = `${timestamp}.${rawBody.toString()}`;
const expected = crypto
.createHmac("sha256", secret)
.update(signedPayload)
.digest("hex");
// Timing-safe comparison
try {
const isValid = crypto.timingSafeEqual(
Buffer.from(signature, "hex"),
Buffer.from(expected, "hex")
);
return { valid: isValid };
} catch {
return { valid: false, reason: "Signature length mismatch" };
}
}
```
### Step 4: Express Webhook Handler
```typescript
// src/api/webhooks/elevenlabs.ts
import express from "express";
import { verifyWebhookSignature } from "../../elevenlabs/webhook-verify";
const router = express.Router();
// CRITICAL: Use raw body parser for signature verification
router.post("/webhooks/elevenlabs",
express.raw({ type: "application/json" }),
async (req, res) => {
const signature = req.headers["elevenlabs-signature"] as string;
const secret = process.env.ELEVENLABS_WEBHOOK_SECRET!;
const { valid, reason } = verifyWebhookSignature(req.body, signature, secret);
if (!valid) {
console.error("Webhook verification failed:", reason);
return res.status(401).json({ error: "Invalid signature" });
}
// Return 200 immediately to prevent webhook auto-disable
res.status(200).json({ received: true });
// Process asynchronously
const event = JSON.parse(req.body.toString());
processEvent(event).catch(err =>
console.error("Webhook processing failed:", err)
);
}
);
// Event routing
async function processEvent(event: any) {
const eventType = event.type || event.event_type;
switch (eventType) {
case "post_call_transcription":
await handleTranscription(event);
break;
case "post_call_audio":
await handleCallAudio(event);
break;
case "call_initiation_failure":
await handleCallFailure(event);
break;
case "speech_to_text.completed":
await handleSTTCompleted(event);
break;
default:
console.log("Unhandled event type:", eventType);
}
}
```
### Step 5: Event Handlers
```typescript
// Conversational AI post-call transcript
async function handleTranscription(event: any) {
const {
conversation_id,
transcript, // Full conversation text
analysis, // AI analysis of the call
metadata, // Custom metadata from agent config
recording_url, // Audio recording URL (if enabled)
} = event.data;
console.log(`[Transcript] Conversation ${conversation_id}`);
console.log(`Transcript: ${transcript?.substring(0, 200)}...`);
// Store in your database
// await db.conversations.upsert({ conversation_id, transcript, analysis });
}
// Post-call audio recording
async function handleCallAudio(event: any) {
const {
conversation_id,
audio_base64, // Base64-encoded audio of the full conversation
} = event.data;
if (audio_base64) {
const audioBuffer = Buffer.from(audio_base64, "base64");
console.log(`[Audio] Received ${audioBuffer.length} bytes for ${conversation_id}`);
// Save audio: await fs.writeFile(`recordings/${conversation_id}.mp3`, audioBuffer);
}
}
// Failed outbound call
async function handleCallFailure(event: any) {
const {
conversation_id,
failure_reason,
metadata,
} = event.data;
console.error(`[Call Failed] ${conversation_id}: ${failure_reason}`);
// Alert: await alerting.notify("Call initiation failed", { conversation_id, failure_reason });
}
// Async Speech-to-Text completion
async function handleSTTCompleted(event: any) {
const {
transcription_id,
text,
words, // Word-level timestamps
language,
} = event.data;
console.log(`[STT Complete] ${transcription_id}: ${language}`);
console.log(`Text: ${text?.substring(0, 200)}...`);
// Process transcription results
}
```
### Step 6: Idempotency Protection
```typescript
// Prevent duplicate processing if ElevenLabs retries delivery
const processedEvents = new Set<string>();
async function withIdempotency(
eventId: string,
handler: () => Promise<void>
): Promise<void> {
if (processedEvents.has(eventId)) {
console.log(`Event ${eventId} already processed, skipping`);
return;
}
await handler();
processedEvents.add(eventId);
// Clean up old entries (in production, use Redis with TTL)
if (processedEvents.size > 10000) {
const oldest = Array.from(processedEvents).slice(0, 5000);
oldest.forEach(id => processedEvents.delete(id));
}
}
```
### Step 7: Local Testing with ngrok
```bash
# Expose local server to internet
ngrok http 3000
# Use the ngrok URL as webhook endpoint in ElevenLabs dashboard
# https://abc123.ngrok.io/webhooks/elevenlabs
# Test with curl (simulated event)
curl -X POST http://localhost:3000/webhooks/elevenlabs \
-H "Content-Type: application/json" \
-H "ElevenLabs-Signature: t=$(date +%s),v1=test" \
-d '{"type":"speech_to_text.completed","data":{"text":"Hello world"}}'
```
## Webhook Reliability
| Behavior | Detail |
|----------|--------|
| Retry policy | ElevenLabs retries failed deliveries |
| Auto-disable | After 10 consecutive failures AND 7+ days since last success |
| Timeout | Your endpoint must respond within a few seconds |
| Re-enable | Manually re-enable in dashboard after fixing the endpoint |
| Authentication | HMAC-SHA256 via `ElevenLabs-Signature` header |
## Error Handling
| Issue | Cause | Solution |
|-------|-------|----------|
| Signature mismatch | Wrong secret or body parsing | Use `express.raw()`, verify secret matches dashboard |
| Webhook auto-disabled | 10+ consecutive failures | Fix endpoint, re-enable in dashboard |
| Duplicate events | Retried delivery | Implement idempotency with event ID tracking |
| Handler timeout | Slow processing | Return 200 immediately, process async |
| Replay attack | Old timestamp reused | Check timestamp age (reject > 5 min) |
## Resources
- [ElevenLabs Webhooks Guide](https://elevenlabs.io/docs/overview/administration/webhooks)
- [Post-Call Webhooks](https://elevenlabs.io/docs/agents-platform/workflows/post-call-webhooks)
- [STT Webhooks](https://elevenlabs.io/docs/cookbooks/speech-to-text/webhooks)
- [Webhook API Reference](https://elevenlabs.io/docs/api-reference/webhooks/list)
## Next Steps
For performance optimization, see `elevenlabs-performance-tuning`.Related Skills
server-sent-events-setup
Server Sent Events Setup - Auto-activating skill for API Integration. Triggers on: server sent events setup, server sent events setup Part of the API Integration skill category.
exa-webhooks-events
Build event-driven integrations with Exa using scheduled monitors and content alerts. Use when building content monitoring, competitive intelligence pipelines, or scheduled search automation with Exa. Trigger with phrases like "exa monitor", "exa content alerts", "exa scheduled search", "exa event-driven", "exa notifications".
evernote-webhooks-events
Implement Evernote webhook notifications and sync events. Use when handling note changes, implementing real-time sync, or processing Evernote notifications. Trigger with phrases like "evernote webhook", "evernote events", "evernote sync", "evernote notifications".
emitting-api-events
Build event-driven APIs with webhooks, Server-Sent Events, and real-time notifications. Use when building event-driven API architectures. Trigger with phrases like "add webhooks", "implement events", or "create event-driven API".
elevenlabs-upgrade-migration
Upgrade ElevenLabs SDK versions and migrate between API model generations. Use when upgrading the elevenlabs-js or elevenlabs Python SDK, migrating from v1 to v2 models, or handling deprecations. Trigger: "upgrade elevenlabs", "elevenlabs migration", "elevenlabs breaking changes", "update elevenlabs SDK", "migrate elevenlabs model", "eleven_v3 migration".
elevenlabs-security-basics
Apply ElevenLabs security best practices for API keys, webhook HMAC validation, and voice data protection. Use when securing API keys, validating webhook signatures, or auditing ElevenLabs security configuration. Trigger: "elevenlabs security", "elevenlabs secrets", "secure elevenlabs", "elevenlabs API key security", "elevenlabs webhook signature", "elevenlabs HMAC".
elevenlabs-sdk-patterns
Apply production-ready ElevenLabs SDK patterns for TypeScript and Python. Use when implementing ElevenLabs integrations, refactoring SDK usage, or establishing team coding standards for audio AI applications. Trigger: "elevenlabs SDK patterns", "elevenlabs best practices", "elevenlabs code patterns", "idiomatic elevenlabs", "elevenlabs typescript".
elevenlabs-reference-architecture
Implement ElevenLabs reference architecture for production TTS/voice applications. Use when designing new ElevenLabs integrations, reviewing project structure, or building a scalable audio generation service. Trigger: "elevenlabs architecture", "elevenlabs project structure", "how to organize elevenlabs", "TTS service architecture", "elevenlabs design patterns", "voice API architecture".
elevenlabs-rate-limits
Implement ElevenLabs rate limiting, concurrency queuing, and backoff patterns. Use when handling 429 errors, implementing retry logic, or managing concurrent TTS request throughput. Trigger: "elevenlabs rate limit", "elevenlabs throttling", "elevenlabs 429", "elevenlabs retry", "elevenlabs backoff", "elevenlabs concurrent requests".
elevenlabs-prod-checklist
Execute ElevenLabs production deployment checklist with health checks and rollback. Use when deploying TTS/voice integrations to production, preparing for launch, or implementing go-live procedures for ElevenLabs-powered apps. Trigger: "elevenlabs production", "deploy elevenlabs", "elevenlabs go-live", "elevenlabs launch checklist", "production TTS".
elevenlabs-performance-tuning
Optimize ElevenLabs TTS latency with model selection, streaming, caching, and audio format tuning. Use when experiencing slow TTS responses, implementing real-time voice features, or optimizing audio generation throughput. Trigger: "elevenlabs performance", "optimize elevenlabs", "elevenlabs latency", "elevenlabs slow", "fast TTS", "reduce elevenlabs latency", "TTS streaming".
elevenlabs-local-dev-loop
Configure local ElevenLabs development with mocking, hot reload, and audio testing. Use when setting up a dev environment for TTS/voice projects, configuring test workflows, or building a fast iteration cycle with ElevenLabs audio. Trigger: "elevenlabs dev setup", "elevenlabs local development", "elevenlabs dev environment", "develop with elevenlabs", "test elevenlabs locally".