| 422 |
invalidvoicesample |
Clone audio bad format/t
Implement ElevenLabs text-to-speech and voice cloning workflows.
ReadWriteBash(npm:*)Bash(curl:*)
ElevenLabs Core Workflow A — TTS & Voice Cloning
Overview
The primary ElevenLabs workflows: (1) Text-to-Speech with voice settings, (2) Instant Voice Cloning from audio samples, (3) streaming TTS via WebSocket for real-time applications, and (4) voice-library management. This SKILL.md walks the full flow at a high level and carries the first TTS example inline; the deep code for cloning, streaming, and management lives in the full implementation walkthrough.
Prerequisites
- Completed
elevenlabs-install-auth setup
- Valid API key with sufficient character quota
- For voice cloning: audio recording(s) of the target voice (min 30 seconds, clean audio)
Instructions
Step 1: Advanced Text-to-Speech
Instantiate the client, call textToSpeech.convert(voiceId, opts), and pipe the returned stream to a file. The voice_settings block is where you tune delivery:
import { ElevenLabsClient } from "@elevenlabs/elevenlabs-js";
import { createWriteStream } from "fs";
import { Readable } from "stream";
import { pipeline } from "stream/promises";
const client = new ElevenLabsClient();
async function generateSpeech(
text: string,
voiceId: string,
outputPath: string
) {
const audio = await client.textToSpeech.convert(voiceId, {
text,
model_id: "eleven_multilingual_v2",
voice_settings: {
stability: 0.5, // Lower = more expressive, higher = more consistent
similarity_boost: 0.75, // How closely to match the original voice
style: 0.3, // Amplify the speaker's style (adds latency if > 0)
speed: 1.0, // 0.7 to 1.2 range
},
// Optional: enforce language for multilingual model
// language_code: "en", // ISO 639-1
});
await pipeline(Readable.fromWeb(audio as any), createWriteStream(outputPath));
console.log(`Generated: ${outputPath}`);
}
await generateSpeech("Welcome to our platform.", "21m00Tcm4TlvDq8ikWAM", "stable.mp3");
Step 2: Instant Voice Cloning (IVC)
Clone a voice from 1-25 audio samples with client.voices.add({ name, description, files }), which returns a voiceid you can use immediately in textToSpeech.convert. Use similarityboost: 0.85 on cloned voices to stay close to the original. Full cloneVoice implementation: implementation.md, Step 2.
Step 3: WebSocket Streaming TTS
For real-time apps (chatbots, live narration), open wss://api.elevenlabs.io/v1/text-to-speech/{voiceId}/stream-input with the low-latency elevenflashv2_5 model. Send a space as Beginning-of-Stream, stream
Implement ElevenLabs speech-to-speech, sound effects, audio isolation, and speech-to-text.
ReadWriteBash(npm:*)Bash(curl:*)
ElevenLabs Core Workflow B — Speech-to-Speech, Sound Effects & Audio Isolation
Overview
Secondary ElevenLabs workflows beyond TTS: (1) Speech-to-Speech voice conversion,
(2) Sound Effects generation from text descriptions, (3) Audio Isolation for noise
removal, and (4) Speech-to-Text transcription. Each maps to one API endpoint and
has both a TypeScript SDK and a cURL path.
Full code for every step lives in references/implementation.md;
copy-ready invocations are in references/examples.md.
Prerequisites
- Completed
elevenlabs-install-auth setup.
- For STS: source audio file in MP3/WAV/M4A format.
- For audio isolation: noisy audio file to clean.
Authentication
The SDK client (new ElevenLabsClient()) reads the API key from the
ELEVENLABSAPIKEY environment variable automatically — never hardcode it. cURL
requests send it as the xi-api-key: ${ELEVENLABSAPIKEY} header. Full auth setup
is covered by the elevenlabs-install-auth skill.
Instructions
Import the SDK once, then call the relevant module. The client authenticates from
the environment:
import { ElevenLabsClient } from "@elevenlabs/elevenlabs-js";
import { createReadStream, createWriteStream } from "fs";
import { Readable } from "stream";
import { pipeline } from "stream/promises";
const client = new ElevenLabsClient();
- Speech-to-Speech (voice changer) —
client.speechToSpeech.convert(voiceId, …)
against POST /v1/speech-to-speech/{voiceid}. Use modelid: "elevenenglishsts_v2"
and set removebackgroundnoise: true for built-in cleanup.
- Sound Effects —
client.textToSoundEffects.convert({ text, … }) against
POST /v1/sound-generation. Tune duration_seconds (0.5–30) and
prompt_influence (0–1; higher follows the prompt more closely).
- Audio Isolation —
client.audioIsolation.audioIsolation({ audio }) against
POST /v1/audio-isolation, or the streaming variant for large files.
- Speech-to-Text —
client.speechToText.convert({ audio, modelid: "scribev1" })
against POST /v1/speech-to-text; optionally enable diarize and word timestamps.
Each returns an audio stream (steps 1–3) piped to disk, or a transcript object
(step 4). See references/implementation.md for the
Optimize ElevenLabs costs through model selection, character-efficient patterns, caching, and usage monitoring with budget alerts.
ReadBash(curl:*)Bash(node:*)
ElevenLabs Cost Tuning
Overview
Optimize ElevenLabs costs through model selection (Flash = 50% savings), character-efficient text processing, audio caching, and real-time quota monitoring. ElevenLabs bills by character for TTS and by audio minute for STT.
Prerequisites
- ElevenLabs account with usage dashboard access
- Understanding of your monthly character consumption
- Access to billing at https://elevenlabs.io/app/subscription
Instructions
Step 1: Understand the Billing Model
TTS billing (by character):
| Model |
Credits per Character |
10K Chars Cost |
Best For |
eleven_v3 |
1.0 |
10,000 credits |
Maximum quality |
elevenmultilingualv2 |
1.0 |
10,000 credits |
High quality + multilingual |
elevenflashv2_5 |
0.5 |
5,000 credits |
Real-time / budget-conscious |
eleventurbov2_5 |
0.5 |
5,000 credits |
Fast + affordable |
Other feature billing:
| Feature |
Billing Basis |
| Speech-to-Text (Scribe) |
Per audio minute |
| Sound Effects |
Per generation |
| Audio Isolation |
1,000 characters per minute of audio |
| Dubbing |
Per source audio minute |
Plan character limits:
| Plan |
Monthly |
Price |
Cost/1K Chars |
| Free |
10,000 |
$0 |
$0 |
| Starter |
30,000 |
$5 |
$0.17 |
| Creator |
100,000 |
$22 |
$0.22 |
| Pro |
500,000 |
$99 |
$0.20 |
| Scale |
2,000,000 |
$330 |
$0.17 |
Steps 2–6: Apply the cost levers
Work through the levers in order of savings-per-effort. Each ships as a small, drop-in
TypeScript helper — the full source for every step is in
implementation.md.
- Model-based reduction — route each request through
selectCostEffectiveModel() so
functional audio (greetings, notifications) uses Flash/Turbo at 0.5x while premium,
customer-facing output keeps full-quality models. Biggest single win (50%).
- Character-efficient text — run copy through
optimizeTextForTTS() to strip
markdown, HTML, and redundant whitespace/punctuation before billing counts it (5–15%).
Collect ElevenLabs debug evidence for support tickets and troubleshooting.
Bash(grep:*)Bash(curl:*)Bash(tar:*)Bash(node:*)
ElevenLabs Debug Bundle
Overview
Collect all diagnostic information needed for ElevenLabs support tickets. Gathers SDK version, API connectivity (HTTP status, DNS, TLS), quota status, voice inventory, and model availability into a single archive while redacting all secrets before anything touches disk.
Two collection paths are available and produce equivalent evidence: a shell script (no code dependency — good for servers and CI) and a programmatic TypeScript collector (good when the app already imports the SDK). The full, ready-to-run source for both lives in references/implementation.md; this file is the high-level workflow.
Prerequisites
- ElevenLabs SDK installed
- API key configured (to test connectivity)
- Access to application logs
jq available (used by the shell script to format API responses)
Instructions
The workflow is three steps: run a collector, review the output for stray secrets, then attach it to a support ticket. Follow the summary here and open references/implementation.md for the complete scripts.
Step 1: Run a collector
Shell path — the script writes each section to summary.txt, redacts secrets, then tars and removes the working directory. The skeleton:
#!/bin/bash
# elevenlabs-debug-bundle.sh
set -euo pipefail
BUNDLE_DIR="elevenlabs-debug-$(date +%Y%m%d-%H%M%S)"
mkdir -p "$BUNDLE_DIR"
# ... collect environment, SDK versions, connectivity, quota, voices, models ...
tar -czf "$BUNDLE_DIR.tar.gz" "$BUNDLE_DIR" && rm -rf "$BUNDLE_DIR"
echo "Bundle created: $BUNDLE_DIR.tar.gz"
Programmatic path — build a structured DebugReport when the SDK is already a dependency. Each section is wrapped independently so one failure still returns a partial report:
const report = await collectDebugReport();
console.log(JSON.stringify(report, null, 2));
Full source for both, including the connectivity/TLS probes and quota/voice/model collectors: references/implementation.md.
Step 2: Review for secrets
Inspect the archive before sharing — API keys, webhook secrets, and any .env value are redacted automatically, but confirm nothing sensitive slipped into an error log or stack trace.
Step 3: Submit to support
Open a ticket at https://help.elevenlabs.io, attach the bundle, and describe what you expected, what happened, steps to reproduce, and any request IDs from error responses.
Output
elevenlabs-debug-YYYYMMDD-HHMMSS.tar.gz archive containing:
summary.txt — Environment, SDK
Deploy ElevenLabs TTS applications to Vercel, Fly.
ReadWriteEditBash(vercel:*)Bash(fly:*)Bash(gcloud:*)
ElevenLabs Deploy Integration
Overview
Deploy ElevenLabs TTS/voice applications to Vercel (serverless), Fly.io
(containers), or Google Cloud Run with proper secrets management, timeout
configuration, and streaming support. Pick the platform that matches your
traffic shape, write the platform config + server code, store the API key as a
platform secret, then deploy and smoke-test the live endpoint.
Prerequisites
- ElevenLabs API key for production
- Platform CLI installed (
vercel, fly, or gcloud)
- Application code tested locally
Instructions
Follow these steps. The lean skeleton is below; the full config files and
server code for each platform are in
references/implementation.md.
- Inspect the repo and pick a platform.
Read the existing app code and
any current deploy config, then choose from the comparison table below —
Vercel for a simple stateless TTS API, Fly.io for streaming/WebSocket, Cloud
Run for bursty variable load.
- Write the platform config + server code. Use
Write/Edit to create
the platform files in the repo — vercel.json + the API route for Vercel,
fly.toml + Express server for Fly.io, Dockerfile for Cloud Run. Full
versions are in references/implementation.md.
- Set the API key as a platform secret (never commit it):
vercel env add ELEVENLABS_API_KEY production # Vercel
fly secrets set ELEVENLABS_API_KEY=sk_... # Fly.io
echo -n "sk_..." | gcloud secrets create elevenlabs-api-key --data-file=- # Cloud Run
- Mind the timeout. Vercel Hobby caps functions at 10s (30s on Pro) — use
the elevenflashv2_5 model to stay under it. Fly.io and Cloud Run have no
such short cap.
- Deploy, then smoke-test the live endpoint (see
references/examples.md):
vercel --prod # Vercel
fly deploy # Fly.io
gcloud run deploy tts-service --source . # Cloud Run (see full flags in implementation.md)
Platform Comparison for ElevenLabs
| Feature |
Vercel |
Fly.io |
Cloud Run |
| Max timeout |
30s (Pro) |
No limit |
60min |
| WebSocket streaming |
Limited |
Full support |
Full support |
| Cold start |
~1-3s |
~0.5-2s |
~1-5s |
Generate your first ElevenLabs text-to-speech audio file.
ReadWriteBash(npm:*)Bash(node:*)
ElevenLabs Hello World
Overview
Generate speech from text using the ElevenLabs TTS API. This skill covers the
core POST /v1/text-to-speech/ endpoint with real voice IDs, model
selection, and audio output. Start from the minimal SDK call below, then drill
into the full implementation for the cURL,
streaming, and multi-language paths.
Prerequisites
- Completed the
elevenlabs-install-auth setup skill so the SDK is installed.
- A valid API key exported as
ELEVENLABSAPIKEY in your shell environment.
- Node 20+ (for the TypeScript SDK path) or Python 3.9+ (for the Python path).
Instructions
The whole workflow is one API call: pick a voice ID, pick a model, send text,
write the returned audio stream to a file. The minimal TypeScript path:
import { ElevenLabsClient } from "@elevenlabs/elevenlabs-js";
import { createWriteStream } from "fs";
import { Readable } from "stream";
import { pipeline } from "stream/promises";
const client = new ElevenLabsClient();
const audio = await client.textToSpeech.convert("21m00Tcm4TlvDq8ikWAM", {
text: "Hello! This is your first ElevenLabs text-to-speech generation.",
model_id: "eleven_multilingual_v2",
});
await pipeline(Readable.fromWeb(audio as any), createWriteStream("output.mp3"));
The four generation paths, with full copy-paste code and inline commentary on
every voice_settings field, live in
references/implementation.md:
- SDK (TypeScript / Python) — batch generation with tuned voice settings.
- cURL — the raw REST call, no SDK, for shell scripts and testing.
- Streaming — the
elevenflashv2_5 low-latency path (~75 ms first chunk).
- Model / voice / output-format tables — the exact IDs to plug in above.
Pick the path that matches your stack, swap the voice ID and text, and run it.
Output
A single audio file written to disk (default output.mp3), plus a console line
confirming the write:
output.mp3 — MP3 at mp344100128 by default (~35–50 KB for a one-line
greeting). Override the codec via output_format (see the output-format table
in implementation.md).
- stdout:
Audio saved to output.mp3 (or `Streamed audio saved to
streamed.mp3` on the streaming path).
A non-200 response returns a JSON error body instead of audio — see Error
Handling below.
Error Han
Install and configure ElevenLabs SDK authentication for Node.
WriteBash(npm:*)Bash(pip:*)Bash(pnpm:*)
ElevenLabs Install & Auth
Overview
Set up the ElevenLabs SDK and configure API key authentication. ElevenLabs uses a single API key (xi-api-key header) for all endpoints at api.elevenlabs.io.
Prerequisites
- Node.js 18+ or Python 3.10+
- ElevenLabs account (free tier works) at https://elevenlabs.io
- API key from Profile > API Keys in the ElevenLabs dashboard
Instructions
Step 1: Install the SDK
Node.js (official package: @elevenlabs/elevenlabs-js):
npm install @elevenlabs/elevenlabs-js
# or
pnpm add @elevenlabs/elevenlabs-js
Python (official package: elevenlabs):
pip install elevenlabs
Step 2: Configure API Key
# Set environment variable (all SDKs auto-detect this)
export ELEVENLABS_API_KEY="sk_your_key_here"
# Or create .env file
echo 'ELEVENLABS_API_KEY=sk_your_key_here' >> .env
Add to .gitignore:
.env
.env.local
.env.*.local
Step 3: Initialize the Client
Both SDKs auto-detect ELEVENLABSAPIKEY. Minimal TypeScript skeleton:
import { ElevenLabsClient } from "@elevenlabs/elevenlabs-js";
const client = new ElevenLabsClient({
apiKey: process.env.ELEVENLABS_API_KEY,
});
The Python client mirrors this with ElevenLabsClient(api_key=...). For retry,
timeout, and the full Python skeleton, see
implementation.md.
Step 4: Verify Connection
Confirm auth by listing voices — a successful call proves the key is valid and
not over quota:
const voices = await client.voices.getAll();
console.log(`Connected. ${voices.voices.length} voices available.`);
Full TypeScript + Python + cURL verification (including subscription/quota
inspection) is in implementation.md.
Output
- SDK installed in
node_modules or site-packages
- API key stored in
.env (git-ignored)
- Successful voice listing confirms authentication
- Subscription tier and character quota displayed
Error Handling
| Error |
HTTP |
Cause |
Solution |
invalidapikey |
401 |
Key missing, expired, or malformed |
Regenerate at elevenlabs.io > Profile > API Keys |
ENOTFOUND api.elevenlabs.io |
N/A |
DNS/network failure |
Check internet; ensure outb
Use when setting up a local ElevenLabs dev environment for a TTS/voice project and you need SDK mocking, hot reload, quota-aware iteration, and audio-output testing that does not burn character quota during development.
ReadWriteEditBash(npm:*)Bash(pnpm:*)
ElevenLabs Local Dev Loop
Overview
Set up a fast, cost-effective local development workflow for ElevenLabs audio
projects. The loop centers on three moves — mock the SDK so unit tests never
burn character quota, gate real API calls behind an explicit
ELEVENLABS_INTEGRATION=1 flag, and select a cheaper model in dev while keeping
the high-quality model for production — with tsx watch hot reload and a quota
checker to round out the cycle.
Follow the high-level flow below to scaffold the project, then drill into
references/implementation.md for the full code
of every step and references/examples.md for worked
end-to-end runs.
Prerequisites
Before starting, confirm your environment is ready:
- The
elevenlabs-install-auth setup is complete, so the SDK
(@elevenlabs/elevenlabs-js) is installed and ELEVENLABSAPIKEY is
available in .env.local.
- Node.js 18+ with
npm or pnpm.
vitest installed as the test runner (recommended) — it powers the mock
layer and the integration-test guard.
Instructions
Work through the six steps in order. Each is summarized here; the full code for
every step lives in references/implementation.md.
- Project structure — lay out
src/elevenlabs/ (client, config, tts),
tests/mocks/ and tests/fixtures/sample.mp3, a git-ignored output/,
and .env.local / .env.example. Full tree in the reference.
- Environment configuration — write an environment-aware
config.ts that
picks the model and output format by NODE_ENV. This is the essential
skeleton:
// src/elevenlabs/config.ts
export function loadConfig() {
const env = process.env.NODE_ENV || "development";
return {
apiKey: process.env.ELEVENLABS_API_KEY || "",
// cheaper/faster in dev, best quality in prod
modelId: env === "production"
? "eleven_multilingual_v2" // 1.0 credits/char
: "eleven_flash_v2_5", // 0.5 credits/char, ~75ms
defaultVoiceId: process.env.ELEVENLABS_VOICE_ID || "21m00Tcm4TlvDq8ikWAM",
outputFormat: "mp3_22050_32", // smaller files for dev
};
}
- Mock the SDK — write
tests/mocks/elevenlabs.ts that returns the
sample.mp3 fixture from textToS
Optimize ElevenLabs TTS latency with model selection, streaming, caching, and audio format tuning.
ReadWriteEdit
ElevenLabs Performance Tuning
Overview
Optimize ElevenLabs TTS latency and throughput through model selection, streaming strategies, audio format tuning, and caching. Latency ranges from ~75ms (Flash) to ~500ms (v3) depending on configuration.
The two highest-leverage, lowest-effort levers — model choice (Step 1) and output format (Step 2) — are documented inline below. The four deeper integrations (HTTP streaming, WebSocket streaming, caching, parallel generation) are summarized here with copy-ready code in the full implementation walkthrough.
Prerequisites
- ElevenLabs SDK installed (
@elevenlabs/elevenlabs-js)
- An ElevenLabs API key exported as
ELEVENLABSAPIKEY (used by the SDK and passed as xiapikey on the WebSocket handshake)
- Understanding of your latency requirements
- Audio playback infrastructure (browser, mobile, server-side)
Instructions
Step 1: Model Selection for Latency
The single biggest performance lever is model choice:
| Model |
Avg Latency |
Quality |
Languages |
Use Case |
elevenflashv2_5 |
~75ms |
Good |
32 |
Real-time chat, IVR, gaming |
eleventurbov2_5 |
~150ms |
Good |
32 |
Balanced speed/quality |
elevenmultilingualv2 |
~300ms |
High |
29 |
Narration, content creation |
eleven_v3 |
~500ms |
Highest |
70+ |
Maximum expressiveness |
// Select model based on use case
function selectModel(useCase: "realtime" | "balanced" | "quality" | "max_quality"): string {
const models = {
realtime: "eleven_flash_v2_5",
balanced: "eleven_turbo_v2_5",
quality: "eleven_multilingual_v2",
max_quality: "eleven_v3",
};
return models[useCase];
}
Step 2: Output Format Optimization
Smaller formats = faster transfer:
| Format |
Size/Second |
Quality |
Best For |
mp344100128 |
~16 KB/s |
High |
Downloads, archival |
mp32205032 |
~4 KB/s |
Medium |
Streaming, mobile |
pcm_16000 |
~32 KB/s |
Raw |
Server-side processing |
pcm_44100 |
~88 KB/s |
Raw |
High-quality processing |
ulaw_8000 |
~8 KB/s |
Phone |
Execute an ElevenLabs production deployment checklist with health checks and rollback.
ReadBash(curl:*)Bash(jq:*)Grep
ElevenLabs Production Checklist
Overview
Complete checklist for deploying ElevenLabs TTS/voice integrations to production. Covers
API configuration, health checks, circuit breakers, monitoring, and rollback procedures.
The deep code for the resilience primitives lives in references/ so this file stays a
fast, scannable runbook — drill in when you need the full implementation.
Prerequisites
- Staging environment tested and verified
- Production API key (separate from dev/staging)
- Monitoring and alerting infrastructure ready
Instructions
Step 1: Pre-Deployment Verification
Walk the checklist below. Every unchecked box is a launch blocker.
Configuration:
- [ ] Production API key stored in secure vault (not in code)
- [ ]
ELEVENLABSAPIKEY set in deployment platform's secrets
- [ ] Webhook secret configured (if using webhooks)
- [ ] Using production model ID (
elevenmultilingualv2 or eleven_v3)
Code Quality:
- [ ] All tests passing with mocked ElevenLabs SDK
- [ ] No hardcoded API keys (scan with
grep -r "sk_" src/)
- [ ] Error handling covers 400, 401, 404, 429, 5xx responses
- [ ] Rate limiting implemented matching plan concurrency limit
- [ ] Text splitting handles inputs > 5,000 characters
- [ ] Audio output format appropriate for use case
Quota Planning:
- [ ] Estimated monthly character usage fits within plan limit
- [ ] Usage-based billing enabled (Creator+ plans) if needed
- [ ] Flash/Turbo models used where latency matters more than quality
Step 2: Wire the resilience primitives
Production ElevenLabs integrations need three primitives. The full drop-in TypeScript for
each is in references/implementation.md — high-level intent:
- Health check endpoint — reports connectivity, latency, and remaining quota; returns
degraded past 90% quota and unhealthy on any API failure, so a load balancer can gate
traffic.
- Circuit breaker — opens after N consecutive failures, cools down, then probes
half-open; accepts a fallback (placeholder audio / cached clip / null) so a TTS outage
degrades gracefully instead of throwing.
- Monitoring & alerting — emit one structured metric per TTS call and drive the alert
thresholds in the table below into your observability platform.
Step 3: Run the pre-flight gate
Before promoting a build, run the pre-flight script — it checks connectivity, quota, voice
availabili
Implement ElevenLabs rate limiting, concurrency queuing, and backoff patterns.
ReadWriteEdit
ElevenLabs Rate Limits
Overview
Handle ElevenLabs rate limits with plan-aware concurrency queuing, exponential backoff, and quota monitoring. ElevenLabs uses two rate limit mechanisms: concurrent request limits (per plan) and system-level throttling. The key insight is that a 429 means two different things depending on its detail.status — and each demands the opposite response.
Prerequisites
- ElevenLabs SDK installed (
@elevenlabs/elevenlabs-js)
- Understanding of your subscription plan's limits
p-queue package (recommended): npm install p-queue
Instructions
Step 1: Understand the Two 429 Error Types
ElevenLabs returns HTTP 429 for two different reasons. Read the detail.status field to tell them apart — the correct strategy is opposite for each.
| 429 Variant |
Response Body |
Cause |
Strategy |
toomanyconcurrent_requests |
{"detail":{"status":"toomanyconcurrent_requests"}} |
Exceeded plan concurrency |
Queue requests, don't backoff |
system_busy |
{"detail":{"status":"system_busy"}} |
Server overload |
Exponential backoff |
Step 2: Know Your Plan Concurrency Limits
Concurrency is capped per plan. Size your queue to this number — never higher.
| Plan |
Max Concurrent Requests |
Characters/Month |
| Free |
2 |
10,000 |
| Starter |
3 |
30,000 |
| Creator |
5 |
100,000 |
| Pro |
10 |
500,000 |
| Scale |
15 |
2,000,000 |
| Business |
15 |
Custom |
Step 3: Assemble the Four Building Blocks
Write four small modules and compose them. The full, copy-ready source for each is in references/implementation.md — the skeleton below shows how they fit together.
- Request queue (
rate-limiter.ts) — a p-queue sized to your plan's concurrency limit. This is the response to toomanyconcurrent_requests: queue, do not back off.
- Backoff wrapper (
backoff.ts) — exponential backoff with jitter for system_busy and 5xx; immediate short retry for concurrency; hard-fail on 401/400/404.
- Quota monitor (
quota-monitor.ts) — polls user.subscription character usage, warns at a threshold, and blocks a request that would overrun remaining quota.
- Resilient client (
resilient-c
Implement an ElevenLabs reference architecture for production TTS/voice applications.
Read
ElevenLabs Reference Architecture
Overview
Production-ready architecture for ElevenLabs TTS/voice applications. Covers project
layout, service layers, caching, streaming, and multi-model orchestration. The full
code for each layer lives in references/ so this file stays a navigable map; drill
into a reference file when you need the exact implementation.
Prerequisites
- Understanding of layered architecture patterns
- ElevenLabs SDK knowledge (see
elevenlabs-sdk-patterns)
- TypeScript project with async patterns
- Redis (optional, for distributed caching)
- Auth: an ElevenLabs API key exported as
ELEVENLABSAPIKEY (read by the
config layer). This is the only ElevenLabs credential — your app's own request
auth (middleware/auth.ts) is separate and unrelated.
Instructions
Build the service in six layers. Each step below is the high-level move; the
verbatim code and diagrams are in the linked reference files.
Step 1: Lay out the project
Split the codebase into elevenlabs/ (client, config, models, errors, types),
services/ (tts, voice, audio, cache), api/ (routes + middleware), queue/, and
monitoring/. See the full project tree.
Step 2: Configuration layer
Define an environment-aware ElevenLabsConfig — dev uses the cheap/fast
elevenflashv25 and small output format; production uses elevenmultilingual_v2
at higher quality, more concurrency, and a larger cache. loadConfig() merges the
per-environment defaults with ELEVENLABSAPIKEY. Full interface and ENV_CONFIGS:
implementation walkthrough.
Step 3: TTS service layer
Wrap the SDK client in a TTSService that owns a singleton client and a p-queue
sized to maxConcurrency (this is what prevents 429s). generate() supports both
streaming and buffered convert, logs latency, and routes errors through
classifyError. generateLongText() splits on sentence boundaries under the 5000-char
limit to preserve prosody. Full class:
implementation walkthrough.
Step 4: Voice management service
A VoiceService over the client for list/clone/get-settings/update-settings/delete,
with category filtering (premade / cloned / generated). Full class:
implementation walkthrough.
Step 5: Wire the data flow
Requests flow Client → API layer →
Apply production-ready ElevenLabs SDK patterns for TypeScript and Python.
ReadWriteEdit
ElevenLabs SDK Patterns
Overview
Production-ready patterns for the ElevenLabs TypeScript and Python SDKs. Covers singleton
clients, type-safe TTS wrappers, error classification, retry with a concurrency queue, and
multi-tenant client factories. Adopt them incrementally — the singleton client alone fixes the
most common mistakes; add error classification and the queue as throughput grows.
The full, copy-ready code for all six patterns lives in
references/implementation.md. This file gives the high-level
workflow plus the essential skeleton so you can follow it end to end, then drill into the
reference for depth.
Prerequisites
@elevenlabs/elevenlabs-js installed (TypeScript) or elevenlabs (Python)
ELEVENLABSAPIKEY exported in the environment (never hardcode the key)
- Familiarity with async/await patterns and error handling best practices
Instructions
Apply the patterns in order — each builds on the previous one:
- Singleton client. Create one lazily-initialized
ElevenLabsClient guarded by an
ELEVENLABSAPIKEY check so misconfiguration fails fast at startup. Expose a resetClient()
for tests. This is the skeleton every other pattern imports:
let instance: ElevenLabsClient | null = null;
export function getClient(): ElevenLabsClient {
if (!instance) {
if (!process.env.ELEVENLABS_API_KEY) {
throw new Error("ELEVENLABS_API_KEY environment variable is required");
}
instance = new ElevenLabsClient({
apiKey: process.env.ELEVENLABS_API_KEY,
maxRetries: 3,
timeoutInSeconds: 60,
});
}
return instance;
}
- Type-safe TTS service. Wrap
textToSpeech.convert behind a typed TTSOptions interface
and named VoicePreset records (narration / conversational / dramatic / neutral) so voice
settings are compile-time checked and consistent across the codebase.
- Error classification. Map raw SDK errors to an
ElevenLabsServiceError carrying a stable
code (authfailed, quotaexceeded, ratelimited, concurrentlimit, voicenotfound,
invalidrequest, servererror, network_error) and a retryable flag driven by HTTP status.
- Retry with a concurrency queue. Route calls through a
p-queue sized to your plan's
concurrent-request limit, retrying only retryable errors with exponential backoff + jitter.
- Multi-tenant factory. For Saa
Apply ElevenLabs security best practices for API keys, webhook HMAC validation, and voice data protection.
ReadWriteGrep
ElevenLabs Security Basics
Overview
Security best practices for ElevenLabs API key management, webhook HMAC
signature verification, and protecting cloned voice data. ElevenLabs uses a
single API key (xi-api-key) and HMAC webhook authentication.
This SKILL.md carries the workflow at a high level with the essential
skeletons. Full production code for each step lives in
references/implementation.md, and end-to-end
scenarios live in references/examples.md.
Prerequisites
- ElevenLabs SDK installed
- Understanding of environment variables
- Access to ElevenLabs dashboard (Settings > API Keys)
Instructions
Step 1: API Key Management
Keep keys out of source, and add a hook that blocks accidental commits:
# .env (NEVER commit to git)
ELEVENLABS_API_KEY=sk_your_key_here
# .gitignore — MUST include these
.env
.env.local
.env.*.local
#!/bin/bash
# .git/hooks/pre-commit — reject staged ElevenLabs keys
if git diff --cached | grep -qE 'sk_[a-zA-Z0-9]{20,}'; then
echo "ERROR: ElevenLabs API key detected in staged changes!"
echo "Remove the key and use environment variables instead."
exit 1
fi
Step 2: Environment-Specific Keys
Load the key at startup, fail fast when it is missing, and warn if a production
key leaks into development. Full getSecurityConfig() implementation:
references/implementation.md.
Step 3: Webhook HMAC Signature Verification
ElevenLabs webhooks carry an ElevenLabs-Signature header formatted as
t=TIMESTAMP,v1=SIGNATURE. Verify it with HMAC-SHA256, reject timestamps older
than 5 minutes (replay protection), and use a timing-safe comparison. Full
verifyWebhookSignature() implementation:
references/implementation.md.
Step 4: Express Webhook Endpoint with Verification
Verify against the raw request body, respond 200 fast, then process
asynchronously so you never trip the webhook timeout. Full endpoint:
references/implementation.md.
Step 5: API Key Rotation Procedure
Generate the new key, validate it before cutover, push to every environment,
verify production, then revoke the old key — zero downtime. Full runbook:
references/implementation.md.
Step 6: Voice Data Protection
Cloned voices are biometric PII: restrict who can clone, audit-log every
operation, and require documented consent. Full policy and audit logger:
Upgrade ElevenLabs SDK versions and migrate between API model generations.
ReadWriteEditBash(npm:*)Bash(pip:*)Bash(git:*)
ElevenLabs Upgrade & Migration
Overview
Guide for upgrading the ElevenLabs SDK and migrating between model generations.
Covers the JS SDK package rename (community elevenlabs → official
@elevenlabs/elevenlabs-js), model ID changes across generations, voice-settings
evolution, and API endpoint stability.
Work the seven steps below at a high level from this file; drill into
references/migration-guide.md for the full command
set and per-step code, and references/examples.md for three
end-to-end worked scenarios.
Authentication
All API calls authenticate with an account API key passed as the xi-api-key
header. Store it in the ELEVENLABSAPIKEY environment variable — never inline a
key in source. The SDK clients read the same value (process.env.ELEVENLABSAPIKEY
in Node, api_key=... in Python).
Prerequisites
- Current ElevenLabs SDK installed (Node or Python)
ELEVENLABSAPIKEY exported in the environment
- Git for version control
- Test suite available
- Staging environment for validation
Instructions
The migration is a seven-step, branch-isolated workflow. Read package manifests and
config with Read, apply import/model changes with Edit, add new config files
(e.g. config/models.ts) with Write, and run the npm/pip/git commands via
Bash. Full commands and code for each step are in
references/migration-guide.md.
- Check current versions — inspect installed Node/Python SDK versions and list
the models your account can reach.
- JS SDK package migration — uninstall the legacy community
elevenlabs
package, install @elevenlabs/elevenlabs-js, and update imports on an
upgrade/elevenlabs-sdk branch.
- Model migration — map deprecated model IDs to current generations using the
migration table, and add a selectModel() helper that falls back off
eleven_v3 when WebSocket streaming is required.
- Voice settings migration — verify
stability, similarity_boost, style,
and speed against each model's capabilities.
- API endpoint changes — confirm the stable
/v1/ endpoints and adopt the
enhanced /v2/voices search where useful.
- Python SDK upgrade — upgrade, pin the
Implement ElevenLabs webhook HMAC signature verification and event handling.
ReadWriteEditBash(curl:*)
ElevenLabs Webhooks & Events
Overview
ElevenLabs webhooks send HTTP POST notifications when async operations complete: transcription completion, post-call data from Conversational AI agents, and call initiation failures. Every delivery is signed with an HMAC-SHA256 signature you must verify before processing. This skill builds a secure endpoint that verifies signatures, routes events by type, and acks fast to avoid auto-disable.
Prerequisites
- ElevenLabs account (webhooks configured in Settings > Webhooks)
- HTTPS endpoint accessible from the internet
- Webhook secret (generated during webhook creation in dashboard)
Instructions
The full, copy-ready code for each step lives in references/implementation.md; per-event handlers live in references/examples.md. The high-level workflow:
- Know the event types — subscribe only to what you handle (table below).
- Create the webhook in the dashboard (Settings > Webhooks) and copy the HMAC secret.
- Verify the signature with HMAC-SHA256 over
".", using a timing-safe compare and a 5-minute replay window. See the full verifier.
- Handle the request with a raw body parser, ack
200 immediately, then process asynchronously. See the Express handler.
- Route events to per-type handlers. See handler examples.
- Guard against duplicates with idempotency keyed on the event ID. See idempotency.
- Test locally by tunneling with ngrok. See local testing.
Webhook event types
| Event Type |
Payload |
When Triggered |
postcalltranscription |
Full conversation transcript, analysis, metadata |
After Conversational AI call ends |
postcallaudio |
Base64-encoded call audio, minimal metadata |
After call ends (if audio recording enabled) |
callinitiationfailure |
Failure reason, metadata |
When an outbound call fails to connect |
speechtotext.completed |
Transcription result, word timestamps |
Async STT job completes |
Signature verification skeleton
// src/elevenlabs/webhook-verify.ts — Header: t=<unix_ts>,v1=<hex_sig>
export function verifyWebhookSignature(rawBody, signatureHeader, secret)
Ready to use elevenlabs-pack?
|
|