{"id":"bdb43f8d-16d5-4974-9645-8f6fd3703121","shortId":"QCuh2f","kind":"skill","title":"elevenlabs-webhooks","tagline":"Receive and verify ElevenLabs webhooks. Use when setting up ElevenLabs webhook handlers, debugging signature verification, or handling call transcription events.","description":"# ElevenLabs Webhooks\n\n## When to Use This Skill\n\n- Setting up ElevenLabs webhook handlers\n- Debugging signature verification failures\n- Understanding ElevenLabs event types and payloads\n- Processing call transcription events\n- Handling voice removal notifications\n\n## Essential Code\n\n### Signature Verification (SDK — Recommended)\n\nElevenLabs recommends using the official `@elevenlabs/elevenlabs-js` SDK for webhook verification and event construction. See [Verify the webhook secret and construct the webhook payload](https://elevenlabs.io/docs/agents-platform/guides/integrations/upstash-redis#verify-the-webhook-secret-and-consrtuct-the-webhook-payload).\n\n```javascript\n// Express.js / Node example\nconst { ElevenLabsClient } = require('@elevenlabs/elevenlabs-js');\n\nconst elevenlabs = new ElevenLabsClient({\n  apiKey: process.env.ELEVENLABS_API_KEY || 'webhook-only'\n});\n\n// In your webhook handler: get raw body and signature header, then:\nconst event = await elevenlabs.webhooks.constructEvent(rawBody, signatureHeader, process.env.ELEVENLABS_WEBHOOK_SECRET);\n// event is the parsed payload; SDK throws on invalid signature\n```\n\n```typescript\n// Next.js example\nimport { ElevenLabsClient } from '@elevenlabs/elevenlabs-js';\n\nconst elevenlabs = new ElevenLabsClient({\n  apiKey: process.env.ELEVENLABS_API_KEY || 'webhook-only'\n});\n\nexport async function POST(request: NextRequest) {\n  const rawBody = await request.text();\n  const signatureHeader = request.headers.get('ElevenLabs-Signature');\n  try {\n    const event = await elevenlabs.webhooks.constructEvent(\n      rawBody,\n      signatureHeader,\n      process.env.ELEVENLABS_WEBHOOK_SECRET\n    );\n    // Handle event.type, event.data...\n    return new NextResponse('OK', { status: 200 });\n  } catch (error) {\n    return NextResponse.json({ error: (error as Error).message }, { status: 401 });\n  }\n}\n```\n\n### Python SDK Verification (FastAPI)\n\n```python\nimport os\nfrom fastapi import FastAPI, Request, HTTPException\nfrom elevenlabs import ElevenLabs\nfrom elevenlabs.errors import BadRequestError\n\napp = FastAPI()\nelevenlabs = ElevenLabs(api_key=os.environ.get(\"ELEVENLABS_API_KEY\") or \"webhook-only\")\n\n@app.post(\"/webhooks/elevenlabs\")\nasync def elevenlabs_webhook(request: Request):\n    raw_body = await request.body()\n    sig = request.headers.get(\"ElevenLabs-Signature\") or request.headers.get(\"elevenlabs-signature\")\n    \n    if not sig:\n        raise HTTPException(status_code=400, detail=\"Missing signature header\")\n    \n    try:\n        event = elevenlabs.webhooks.construct_event(\n            raw_body.decode(\"utf-8\"),\n            sig,\n            os.environ[\"ELEVENLABS_WEBHOOK_SECRET\"]\n        )\n        # Handle event[\"type\"], event[\"data\"]...\n        return {\"status\": \"ok\"}\n    except BadRequestError as e:\n        raise HTTPException(status_code=401, detail=\"Invalid signature\")\n```\n\nThe SDK (Node/TypeScript and Python) verifies the signature, validates the timestamp (30-minute tolerance), and returns the parsed event. On failure it throws; return 401 and the error message.\n\n## Common Event Types\n\n| Event | Triggered When | Common Use Cases |\n|-------|----------------|------------------|\n| `post_call_transcription` | Call analysis completed | Process call insights, save transcripts |\n| `voice_removal_notice` | Notice that voice will be removed | Notify users, backup voice data |\n| `voice_removal_notice_withdrawn` | Voice removal notice cancelled | Update user notifications |\n| `voice_removed` | Voice has been removed | Clean up voice data, update UI |\n\n## Environment Variables\n\n```bash\nELEVENLABS_WEBHOOK_SECRET=your_webhook_secret_here\n```\n\n## Local Development\n\nFor local webhook testing, install Hookdeck CLI:\n\n```bash\n# Install via npm (recommended)\n\n```\n\nThen start the tunnel:\n\n```bash\nnpx hookdeck-cli listen 3000 elevenlabs --path /webhooks/elevenlabs\n```\n\nNo account required. Provides local tunnel + web UI for inspecting requests.\n\n## Resources\n\n- [Overview](references/overview.md) - What ElevenLabs webhooks are, common event types\n- [Setup](references/setup.md) - Configure webhooks in ElevenLabs dashboard, get signing secret\n- [Verification](references/verification.md) - Signature verification details and gotchas\n- [Express Example](examples/express/) - Complete Express.js implementation\n- [Next.js Example](examples/nextjs/) - Next.js App Router implementation\n- [FastAPI Example](examples/fastapi/) - Python FastAPI implementation\n\n## Recommended: webhook-handler-patterns\n\nWe recommend installing the [webhook-handler-patterns](https://github.com/hookdeck/webhook-skills/tree/main/skills/webhook-handler-patterns) skill alongside this one for handler sequence, idempotency, error handling, and retry logic. Key references (open on GitHub):\n\n- [Handler sequence](https://github.com/hookdeck/webhook-skills/blob/main/skills/webhook-handler-patterns/references/handler-sequence.md) — Verify first, parse second, handle idempotently third\n- [Idempotency](https://github.com/hookdeck/webhook-skills/blob/main/skills/webhook-handler-patterns/references/idempotency.md) — Prevent duplicate processing\n- [Error handling](https://github.com/hookdeck/webhook-skills/blob/main/skills/webhook-handler-patterns/references/error-handling.md) — Return codes, logging, dead letter queues\n- [Retry logic](https://github.com/hookdeck/webhook-skills/blob/main/skills/webhook-handler-patterns/references/retry-logic.md) — Provider retry schedules, backoff patterns\n\n## Related Skills\n\n- [stripe-webhooks](https://github.com/hookdeck/webhook-skills/tree/main/skills/stripe-webhooks) - Stripe payment webhook handling\n- [shopify-webhooks](https://github.com/hookdeck/webhook-skills/tree/main/skills/shopify-webhooks) - Shopify e-commerce webhook handling\n- [github-webhooks](https://github.com/hookdeck/webhook-skills/tree/main/skills/github-webhooks) - GitHub repository webhook handling\n- [resend-webhooks](https://github.com/hookdeck/webhook-skills/tree/main/skills/resend-webhooks) - Resend email webhook handling\n- [chargebee-webhooks](https://github.com/hookdeck/webhook-skills/tree/main/skills/chargebee-webhooks) - Chargebee billing webhook handling\n- [clerk-webhooks](https://github.com/hookdeck/webhook-skills/tree/main/skills/clerk-webhooks) - Clerk auth webhook handling\n- [openai-webhooks](https://github.com/hookdeck/webhook-skills/tree/main/skills/openai-webhooks) - OpenAI webhook handling\n- [paddle-webhooks](https://github.com/hookdeck/webhook-skills/tree/main/skills/paddle-webhooks) - Paddle billing webhook handling\n- [webhook-handler-patterns](https://github.com/hookdeck/webhook-skills/tree/main/skills/webhook-handler-patterns) - Handler sequence, idempotency, error handling, retry logic\n- [hookdeck-event-gateway](https://github.com/hookdeck/webhook-skills/tree/main/skills/hookdeck-event-gateway) - Webhook infrastructure that replaces your queue — guaranteed delivery, automatic retries, replay, rate limiting, and observability for your webhook handlers\n\n## Official ElevenLabs SDK Skills\n\nFor making API calls TO ElevenLabs (text-to-speech, transcription, agents), see the official [ElevenLabs Skills](https://github.com/elevenlabs/skills). This skill handles the opposite direction: receiving webhooks FROM ElevenLabs.\n\n> **SDK Warning:** Always use `@elevenlabs/elevenlabs-js` for JavaScript. Do not use `npm install elevenlabs` (that's an outdated v1.x package).","tags":["elevenlabs","webhooks","webhook","skills","hookdeck","agent-skills","ai-coding","api-integrations","event-driven","github-webhooks","llm-tools","shopify-webhooks"],"capabilities":["skill","source-hookdeck","skill-elevenlabs-webhooks","topic-agent-skills","topic-ai-coding","topic-api-integrations","topic-event-driven","topic-github-webhooks","topic-llm-tools","topic-shopify-webhooks","topic-stripe-webhooks","topic-webhook-security","topic-webhook-signatures","topic-webhooks"],"categories":["webhook-skills"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/hookdeck/webhook-skills/elevenlabs-webhooks","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add hookdeck/webhook-skills","source_repo":"https://github.com/hookdeck/webhook-skills","install_from":"skills.sh"}},"qualityScore":"0.485","qualityRationale":"deterministic score 0.48 from registry signals: · indexed on github topic:agent-skills · 71 github stars · SKILL.md body (7,383 chars)","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill-github:v1","enrichmentVersion":1,"enrichedAt":"2026-05-18T18:56:53.237Z","embedding":null,"createdAt":"2026-04-18T22:13:51.518Z","updatedAt":"2026-05-18T18:56:53.237Z","lastSeenAt":"2026-05-18T18:56:53.237Z","tsv":"'-8':274 '/docs/agents-platform/guides/integrations/upstash-redis#verify-the-webhook-secret-and-consrtuct-the-webhook-payload).':85 '/elevenlabs/skills).':701 '/hookdeck/webhook-skills/blob/main/skills/webhook-handler-patterns/references/error-handling.md)':538 '/hookdeck/webhook-skills/blob/main/skills/webhook-handler-patterns/references/handler-sequence.md)':519 '/hookdeck/webhook-skills/blob/main/skills/webhook-handler-patterns/references/idempotency.md)':530 '/hookdeck/webhook-skills/blob/main/skills/webhook-handler-patterns/references/retry-logic.md)':549 '/hookdeck/webhook-skills/tree/main/skills/chargebee-webhooks)':604 '/hookdeck/webhook-skills/tree/main/skills/clerk-webhooks)':614 '/hookdeck/webhook-skills/tree/main/skills/github-webhooks)':584 '/hookdeck/webhook-skills/tree/main/skills/hookdeck-event-gateway)':658 '/hookdeck/webhook-skills/tree/main/skills/openai-webhooks)':624 '/hookdeck/webhook-skills/tree/main/skills/paddle-webhooks)':633 '/hookdeck/webhook-skills/tree/main/skills/resend-webhooks)':594 '/hookdeck/webhook-skills/tree/main/skills/shopify-webhooks)':572 '/hookdeck/webhook-skills/tree/main/skills/stripe-webhooks)':562 '/hookdeck/webhook-skills/tree/main/skills/webhook-handler-patterns)':496,644 '/webhooks/elevenlabs':235,423 '200':187 '30':311 '3000':420 '400':263 '401':198,296,324 'account':425 'agent':693 'alongsid':498 'alway':714 'analysi':342 'api':100,148,224,228,684 'apikey':98,146 'app':220,472 'app.post':234 'async':154,236 'auth':616 'automat':667 'await':118,161,172,244 'backoff':553 'backup':360 'badrequesterror':219,289 'bash':388,405,414 'bill':606,635 'bodi':111,243 'call':21,47,339,341,345,685 'cancel':370 'case':337 'catch':188 'chargebe':600,605 'chargebee-webhook':599 'clean':380 'clerk':610,615 'clerk-webhook':609 'cli':404,418 'code':55,262,295,540 'commerc':576 'common':329,335,442 'complet':343,465 'configur':447 'const':90,94,116,142,159,163,170 'construct':72,79 'dashboard':451 'data':284,362,383 'dead':542 'debug':16,36 'def':237 'deliveri':666 'detail':264,297,459 'develop':397 'direct':707 'duplic':532 'e':291,575 'e-commerc':574 'elevenlab':2,7,13,24,33,41,60,95,143,167,213,215,222,223,227,238,249,254,277,389,421,439,450,679,687,697,711,724 'elevenlabs-signatur':166,248,253 'elevenlabs-webhook':1 'elevenlabs.errors':217 'elevenlabs.io':84 'elevenlabs.io/docs/agents-platform/guides/integrations/upstash-redis#verify-the-webhook-secret-and-consrtuct-the-webhook-payload).':83 'elevenlabs.webhooks.construct':270 'elevenlabs.webhooks.constructevent':119,173 'elevenlabs/elevenlabs-js':65,93,141,716 'elevenlabscli':91,97,139,145 'email':596 'environ':386 'error':189,192,193,195,327,505,534,648 'essenti':54 'event':23,42,49,71,117,125,171,269,271,281,283,318,330,332,443,654 'event.data':181 'event.type':180 'exampl':89,137,463,469,476 'examples/express':464 'examples/fastapi':477 'examples/nextjs':470 'except':288 'export':153 'express':462 'express.js':87,466 'failur':39,320 'fastapi':202,207,209,221,475,479 'first':521 'function':155 'gateway':655 'get':109,452 'github':514,580,585 'github-webhook':579 'github.com':495,518,529,537,548,561,571,583,593,603,613,623,632,643,657,700 'github.com/elevenlabs/skills).':699 'github.com/hookdeck/webhook-skills/blob/main/skills/webhook-handler-patterns/references/error-handling.md)':536 'github.com/hookdeck/webhook-skills/blob/main/skills/webhook-handler-patterns/references/handler-sequence.md)':517 'github.com/hookdeck/webhook-skills/blob/main/skills/webhook-handler-patterns/references/idempotency.md)':528 'github.com/hookdeck/webhook-skills/blob/main/skills/webhook-handler-patterns/references/retry-logic.md)':547 'github.com/hookdeck/webhook-skills/tree/main/skills/chargebee-webhooks)':602 'github.com/hookdeck/webhook-skills/tree/main/skills/clerk-webhooks)':612 'github.com/hookdeck/webhook-skills/tree/main/skills/github-webhooks)':582 'github.com/hookdeck/webhook-skills/tree/main/skills/hookdeck-event-gateway)':656 'github.com/hookdeck/webhook-skills/tree/main/skills/openai-webhooks)':622 'github.com/hookdeck/webhook-skills/tree/main/skills/paddle-webhooks)':631 'github.com/hookdeck/webhook-skills/tree/main/skills/resend-webhooks)':592 'github.com/hookdeck/webhook-skills/tree/main/skills/shopify-webhooks)':570 'github.com/hookdeck/webhook-skills/tree/main/skills/stripe-webhooks)':560 'github.com/hookdeck/webhook-skills/tree/main/skills/webhook-handler-patterns)':494,642 'gotcha':461 'guarante':665 'handl':20,50,179,280,506,524,535,566,578,588,598,608,618,627,637,649,704 'handler':15,35,108,484,492,502,515,640,645,677 'header':114,267 'hookdeck':403,417,653 'hookdeck-c':416 'hookdeck-event-gateway':652 'httpexcept':211,260,293 'idempot':504,525,527,647 'implement':467,474,480 'import':138,204,208,214,218 'infrastructur':660 'insight':346 'inspect':433 'instal':402,406,488,723 'invalid':133,298 'javascript':86,718 'key':101,149,225,229,510 'letter':543 'limit':671 'listen':419 'local':396,399,428 'log':541 'logic':509,546,651 'make':683 'messag':196,328 'minut':312 'miss':265 'new':96,144,183 'next.js':136,468,471 'nextrequest':158 'nextrespons':184 'nextresponse.json':191 'node':88 'node/typescript':302 'notic':351,352,365,369 'notif':53,373 'notifi':358 'npm':408,722 'npx':415 'observ':673 'offici':64,678,696 'ok':185,287 'one':500 'open':512 'openai':620,625 'openai-webhook':619 'opposit':706 'os':205 'os.environ':276 'os.environ.get':226 'outdat':728 'overview':436 'packag':730 'paddl':629,634 'paddle-webhook':628 'pars':128,317,522 'path':422 'pattern':485,493,554,641 'payload':45,82,129 'payment':564 'post':156,338 'prevent':531 'process':46,344,533 'process.env.elevenlabs':99,122,147,176 'provid':427,550 'python':199,203,304,478 'queue':544,664 'rais':259,292 'rate':670 'raw':110,242 'raw_body.decode':272 'rawbodi':120,160,174 'receiv':4,708 'recommend':59,61,409,481,487 'refer':511 'references/overview.md':437 'references/setup.md':446 'references/verification.md':456 'relat':555 'remov':52,350,357,364,368,375,379 'replac':662 'replay':669 'repositori':586 'request':157,210,240,241,434 'request.body':245 'request.headers.get':165,247,252 'request.text':162 'requir':92,426 'resend':590,595 'resend-webhook':589 'resourc':435 'retri':508,545,551,650,668 'return':182,190,285,315,323,539 'router':473 'save':347 'schedul':552 'sdk':58,66,130,200,301,680,712 'second':523 'secret':77,124,178,279,391,394,454 'see':73,694 'sequenc':503,516,646 'set':11,31 'setup':445 'shopifi':568,573 'shopify-webhook':567 'sig':246,258,275 'sign':453 'signatur':17,37,56,113,134,168,250,255,266,299,307,457 'signaturehead':121,164,175 'skill':30,497,556,681,698,703 'skill-elevenlabs-webhooks' 'source-hookdeck' 'speech':691 'start':411 'status':186,197,261,286,294 'stripe':558,563 'stripe-webhook':557 'test':401 'text':689 'text-to-speech':688 'third':526 'throw':131,322 'timestamp':310 'toler':313 'topic-agent-skills' 'topic-ai-coding' 'topic-api-integrations' 'topic-event-driven' 'topic-github-webhooks' 'topic-llm-tools' 'topic-shopify-webhooks' 'topic-stripe-webhooks' 'topic-webhook-security' 'topic-webhook-signatures' 'topic-webhooks' 'transcript':22,48,340,348,692 'tri':169,268 'trigger':333 'tunnel':413,429 'type':43,282,331,444 'typescript':135 'ui':385,431 'understand':40 'updat':371,384 'use':9,28,62,336,715,721 'user':359,372 'utf':273 'v1.x':729 'valid':308 'variabl':387 'verif':18,38,57,69,201,455,458 'verifi':6,74,305,520 'via':407 'voic':51,349,354,361,363,367,374,376,382 'warn':713 'web':430 'webhook':3,8,14,25,34,68,76,81,103,107,123,151,177,232,239,278,390,393,400,440,448,483,491,559,565,569,577,581,587,591,597,601,607,611,617,621,626,630,636,639,659,676,709 'webhook-handler-pattern':482,490,638 'webhook-on':102,150,231 'withdrawn':366","prices":[{"id":"acd1155d-4051-4348-bc7e-aac7c6f324c9","listingId":"bdb43f8d-16d5-4974-9645-8f6fd3703121","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"hookdeck","category":"webhook-skills","install_from":"skills.sh"},"createdAt":"2026-04-18T22:13:51.518Z"}],"sources":[{"listingId":"bdb43f8d-16d5-4974-9645-8f6fd3703121","source":"github","sourceId":"hookdeck/webhook-skills/elevenlabs-webhooks","sourceUrl":"https://github.com/hookdeck/webhook-skills/tree/main/skills/elevenlabs-webhooks","isPrimary":false,"firstSeenAt":"2026-04-18T22:13:51.518Z","lastSeenAt":"2026-05-18T18:56:53.237Z"},{"listingId":"bdb43f8d-16d5-4974-9645-8f6fd3703121","source":"skills_sh","sourceId":"hookdeck/webhook-skills/elevenlabs-webhooks","sourceUrl":"https://skills.sh/hookdeck/webhook-skills/elevenlabs-webhooks","isPrimary":true,"firstSeenAt":"2026-05-07T20:44:47.473Z","lastSeenAt":"2026-05-07T22:43:00.386Z"}],"details":{"listingId":"bdb43f8d-16d5-4974-9645-8f6fd3703121","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"hookdeck","slug":"elevenlabs-webhooks","github":{"repo":"hookdeck/webhook-skills","stars":71,"topics":["agent-skills","ai-coding","api-integrations","event-driven","github-webhooks","llm-tools","shopify-webhooks","stripe-webhooks","webhook-security","webhook-signatures","webhooks"],"license":"mit","html_url":"https://github.com/hookdeck/webhook-skills","pushed_at":"2026-05-15T15:30:15Z","description":"Webhook integration skills for AI coding agents (Claude Code, Cursor, Copilot). Step-by-step guidance for setting up webhook receivers, signature verification, and event handling for Stripe, Shopify, GitHub, and more. Built on the Agent Skills specification.","skill_md_sha":"b2e5dbe0fd0853d918d60a3a3d51f6cc8367a6e8","skill_md_path":"skills/elevenlabs-webhooks/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/hookdeck/webhook-skills/tree/main/skills/elevenlabs-webhooks"},"layout":"multi","source":"github","category":"webhook-skills","frontmatter":{"name":"elevenlabs-webhooks","license":"MIT","description":"Receive and verify ElevenLabs webhooks. Use when setting up ElevenLabs webhook handlers, debugging signature verification, or handling call transcription events."},"skills_sh_url":"https://skills.sh/hookdeck/webhook-skills/elevenlabs-webhooks"},"updatedAt":"2026-05-18T18:56:53.237Z"}}