/install runapi-elevenlabs
@runapi.ai/elevenlabs — RunAPI.ai Elevenlabs audio generation
Build Node / TypeScript integrations that generate speech, text-to-dialogue, text-to-sound, speech-to-text, and isolated audio through RunAPI.ai.
Setup
Requires Node 18+ (global fetch).
npm install @runapi.ai/elevenlabs
Set your API key in the environment:
# .env
RUNAPI_API_KEY=runapi_xxx # get one at https://runapi.ai/api_keys
import { ElevenlabsClient } from '@runapi.ai/elevenlabs';
// The SDK reads RUNAPI_API_KEY from the environment automatically.
const client = new ElevenlabsClient();
Pass { apiKey } explicitly if you manage secrets differently. baseUrl defaults to https://runapi.ai; override only for local development.
Core recipe — text to speech
const result = await client.textToSpeech.run({
model: 'text-to-speech-turbo-2-5',
text: 'Hello from RunAPI.',
voice: 'Rachel',
});
const audioUrl = result.audios[0].url;
run() creates the task, auto-polls, and resolves only when the task completes — audios[0].url is guaranteed on the resolved value (for speech-to-text, text is guaranteed). On failure it throws TaskFailedError; on polling timeout it throws TaskTimeoutError. Use run() for scripts and short-lived processes. For request handlers, split it:
const { id } = await client.textToSpeech.create({ model: 'text-to-speech-turbo-2-5', text: '...', voice: 'Rachel' });
// return 202 immediately; fetch later:
const status = await client.textToSpeech.get(id);
if (status.status === 'completed') { /* ... */ }
Do not hold a web worker open waiting on run(). Split + webhook is the production pattern.
run() polls every 2 s for up to 15 min by default. Tune when needed:
await client.textToSpeech.run(params, { maxWaitMs: 2 * 60_000, pollIntervalMs: 1_000 });
If TaskTimeoutError fires, the task is still running server-side — resume with \x3Cresource>.get(id) or finish via webhook.
Multi-voice dialogue
Sequence lines with per-line voice:
const dialogue = await client.textToDialogue.run({
dialogue: [
{ voice: 'Rachel', text: 'So what did you think?' },
{ voice: 'Adam', text: 'Honestly, it was incredible.' },
],
stability: 0.5,
language_code: 'en',
});
console.log(dialogue.audios[0].url);
Sound effects
const fx = await client.textToSound.run({
text: 'Thunderclap followed by rain on a tin roof',
duration_seconds: 6,
loop: false,
output_format: 'mp3_44100_128',
});
Speech to Text (audio in → text out)
const t = await client.speechToText.run({
audio_url: 'https://cdn.example.com/meeting.mp3',
diarize: true,
tag_audio_events: true,
language_code: 'en',
});
console.log(t.text);
Audio isolation (remove background noise)
const isolated = await client.isolateAudio.run({
audio_url: 'https://cdn.example.com/noisy.mp3',
});
console.log(isolated.audios[0].url);
Models
| Resource | model values |
|---|---|
textToSpeech |
text-to-speech-turbo-2-5, text-to-speech-multilingual-v2 |
textToDialogue |
— (no model field; server picks the engine) |
textToSound |
— |
speechToText |
— |
isolateAudio |
— |
Pick the turbo model for the lowest latency; pick multilingual v2 for non-English voices. voice accepts Elevenlabs voice IDs or named voices (e.g. 'Rachel', 'Adam').
Exact credit costs are shown at https://runapi.ai/pricing and in the dashboard — do not hardcode prices in application code.
Callbacks (webhooks)
Pass callback_url on create() (or any run() call) and RunAPI will POST the final payload to you:
await client.textToSpeech.create({
model: 'text-to-speech-turbo-2-5',
text: '...',
voice: 'Rachel',
callback_url: 'https://your.app/webhooks/runapi/elevenlabs',
});
Payload shape (audio resources):
{ id: string; status: 'completed' | 'failed'; audios?: { url: string }[]; error?: string }
SpeechToText return text: string instead of audios.
Always verify the signature before trusting the body. RunAPI signs every callback with your account's Callback Secret (rotate at /accounts/callback_secret). Headers:
X-Callback-Id— UUID, store to make handler idempotentX-Callback-Timestamp— unix seconds, reject if|now - ts| > 300X-Callback-Signature— base64 HMAC-SHA256 over`${id}.${ts}.${rawBody}`using the base64-decoded secret
import crypto from 'node:crypto';
function verify(raw: string, id: string, ts: string, sig: string, secret: string) {
const key = Buffer.from(secret, 'base64');
const mac = crypto.createHmac('sha256', key)
.update(`${id}.${ts}.${raw}`)
.digest('base64');
return crypto.timingSafeEqual(Buffer.from(mac), Buffer.from(sig));
}
Reply 2xx within 10s; any non-2xx triggers retries.
Errors
All errors are re-exported from @runapi.ai/core. Always instanceof — never string-match messages.
| Error | Status | Action |
|---|---|---|
AuthenticationError |
401 | abort; surface "reconnect your API key" |
InsufficientCreditsError |
402 | prompt user to top up at runapi.ai/billing |
ValidationError |
400 / 422 | fix params; do not retry |
RateLimitError |
429 | sleep err.retryAfterMs, then retry |
ServiceUnavailableError |
503 / 455 | retry with backoff; transient service issue |
TaskFailedError |
— | show err.details to user; do not auto-retry |
TaskTimeoutError |
— | re-poll with \x3Cresource>.get(id) |
import { InsufficientCreditsError, TaskFailedError } from '@runapi.ai/elevenlabs';
try {
await client.textToSpeech.run({ model: 'text-to-speech-turbo-2-5', text: '...', voice: 'Rachel' });
} catch (err) {
if (err instanceof InsufficientCreditsError) { /* surface top-up CTA */ }
else if (err instanceof TaskFailedError) { /* show err.details */ }
else throw err;
}
Gotchas
textToSpeechrequiresmodel;textToDialogue,textToSound,speechToText, andisolateAudiodo not take amodelfield.textToDialogueis an array of{ voice, text }lines — voice is per-line, not per-request.text-to-dialogue.stabilityis a fixed enum:0,0.5, or1.speechToText.run()returns{ text }, not{ audios }— the response shape is different from the other resources.output_formatontextToSoundcovers a wide codec/bitrate matrix (mp3_*,pcm_*,ulaw_8000,alaw_8000,opus_*) — pick one from the type union, do not invent strings.callback_urlmust be reachable from the public internet.localhost/127.0.0.1URLs will never fire — use a tunnel (cloudflared, ngrok, tailscale funnel) when developing locally.
Dig deeper
Package README (full API surface, all params): node_modules/@runapi.ai/elevenlabs/README.md. Types: @runapi.ai/elevenlabs/dist/types.d.ts. Product docs: https://runapi.ai/docs.
- 确保已安装 OpenClaw(本地或 Docker 部署)
- 在对话框中输入安装命令:
/install runapi-elevenlabs - 安装完成后,直接呼叫该 Skill 的名称或使用
/runapi-elevenlabs触发 - 根据 Skill 的参数说明提供必要输入,即可获得结构化输出
Elevenlabs 是什么?
Generate and process audio (text-to-speech, multi-voice text-to-dialogue, text-to-sound, speech-to-text, isolate audio) through RunAPI.ai using the @runapi.a... 它是一个面向 Claude Code / OpenClaw 的 AI Agent Skill 插件,目前累计下载 33 次。
如何安装 Elevenlabs?
在 OpenClaw 或 Claude Code 对话框中运行命令「/install runapi-elevenlabs」即可一键安装,无需额外配置。
Elevenlabs 是免费的吗?
是的,Elevenlabs 完全免费,采用 MIT-0 许可证,可自由下载、安装和使用。
Elevenlabs 支持哪些平台?
Elevenlabs 跨平台运行,可在任意部署了 OpenClaw / Claude Code 的环境中使用(cross-platform)。
谁开发了 Elevenlabs?
由 RunAPI(@runapi-ai)开发并维护,当前版本 v0.2.3。