Overview
Expressive speech, one request away.
SecretVoice is a low-latency text-to-speech API tuned for closeness — breathy whispers, intimate narration, and natural conversational turns. Twenty-nine voices across 21 languages, with synchronous, streaming, and realtime WebSocket delivery.
- 29 premade voices — 13 female, 16 male, each with a distinct persona.
- 21 languages — one voice keeps its character in every language.
- Three delivery modes — synchronous audio, HTTP streaming, and realtime WebSocket.
- Drop-in compatibility — point any ElevenLabs client at this API and it works. See Compatibility →
Billing is simple and transparent: you pay for the audio-seconds you produce, tracked live on your balance.
Quickstart
Your first voice in 30 seconds.
Create an account, grab your API key, and synthesize your first line. One endpoint, one body.
{
"text": "Come closer. Let me tell you a secret. Now, just listen to my voice.",
"model_id": "secret-v1"
}
curl -X POST https://api.secretvoice.dev/v1/text-to-speech/velvet \ -H "xi-api-key: $SECRETVOICE_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "text": "Come closer. Let me tell you a secret.", "model_id": "secret-v1" }' \ --output voice.mp3
import requests r = requests.post( "https://api.secretvoice.dev/v1/text-to-speech/velvet", headers={"xi-api-key": "YOUR_KEY", "Content-Type": "application/json"}, json={"text": "Come closer. Let me tell you a secret.", "model_id": "secret-v1"}, ) open("voice.mp3", "wb").write(r.content)
const res = await fetch("https://api.secretvoice.dev/v1/text-to-speech/velvet", { method: "POST", headers: { "xi-api-key": "YOUR_KEY", "Content-Type": "application/json" }, body: JSON.stringify({ text: "Come closer. Let me tell you a secret.", model_id: "secret-v1" }), }); const blob = await res.blob(); const url = URL.createObjectURL(blob); // play or save it
Listen to this exact request. The audio below is the real output of the request above.
Authentication
One header, every request.
All endpoints require your API key, sent as the xi-api-key header. The key is tied to your account and is never shared.
xi-api-key: $SECRETVOICE_API_KEY
- All requests must use HTTPS.
- API keys are scoped to your account and cannot be shared across accounts.
- Requests made without a valid key return 401 with {"detail": "Invalid API key"}.
- Rotating a key invalidates the old one immediately.
Models
One model, tuned for closeness.
SecretVoice exposes a single model, secret-v1, engineered for intimate, expressive delivery. Common model identifiers from compatible clients are accepted as aliases.
Response · 200
{
"models": [{
"model_id": "secret-v1",
"name": "SecretVoice v1",
"can_do_text_to_speech": true,
"can_do_voice_conversion": false,
"languages": ["en", "es", "ja", "fr", "de", "it", "pt", "ru", "zh", "ko", "th", "id", "vi", "ms", "nl", "pl", "et", "fi", "hi", "ta", "cs"]
}]
}
Model aliases
The following identifiers are silently mapped to secret-v1 for compatibility: eleven_multilingual_v2, eleven_flash_v2_5, eleven_turbo_v2_5.
Voices
Twenty-nine voices, tuned for closeness.
Every voice has a distinct persona and keeps its character across all 21 languages. Voice ids are lowercase shorthands.
Response · 200
{
"voices": [{
"voice_id": "velvet",
"name": "Velvet",
"category": "premade",
"labels": { "gender": "female", "style": "rich and luxurious" },
"preview_url": "https://api.secretvoice.dev/v1/voices/velvet/preview.mp3"
}, /* …28 more */]
}
Response · 200
{
"voice_id": "velvet",
"name": "Velvet",
"category": "premade",
"labels": { "gender": "female", "style": "rich and luxurious" },
"preview_url": "https://api.secretvoice.dev/v1/voices/velvet/preview.mp3"
}
Response · 200
{
"stability": 0.5,
"similarity_boost": 0.75,
"style": 0.0,
"speed": 1.0,
"use_speaker_boost": true
}
| Field | Type | Required | Description |
|---|---|---|---|
| stability | number | 0 – 1. Lower = broader emotional range. | |
| similarity_boost | number | 0 – 1. Adherence to the voice's native character. | |
| style | number | 0 – 1. Style exaggeration. Accepted; the signature style is always present. | |
| speed | number | 0.5 – 2.0. 1.0 is default. | |
| use_speaker_boost | boolean | Accepted for compatibility. |
PATCH /v1/voices/velvet/settings
{
"stability": 0.4,
"speed": 0.9
}
The roster
Female
Male
Text to Speech
Convert text to speech.
The core endpoint. Converts text into speech using a voice of your choice and returns the audio file directly.
Query parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| output_format | string | Audio format as codec_sample_rate_bitrate. Default mp3_44100_128. | |
| enable_logging | boolean | Default true. Set false for zero retention (no history). |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
| text | string | yes | The text to synthesize. Cannot be empty. |
| model_id | string | Model to use. Default secret-v1. | |
| language_code | string | ISO 639-1 code to enforce a language. Default en. | |
| voice_settings | object | Per-request voice overrides. See table below. | |
| previous_text | string | Text before this request, for continuity. | |
| next_text | string | Text after this request, for continuity. | |
| apply_text_normalization | enum | auto (default), on, off. | |
| seed | integer | Best-effort deterministic sampling. Accepted; not guaranteed. | |
| pronunciation_dictionary_locators | array | Accepted for compatibility. Reserved for a future release. |
voice_settings
| Field | Type | Required | Description |
|---|---|---|---|
| stability | number | 0 – 1. Lower = broader emotional range. | |
| similarity_boost | number | 0 – 1. Adherence to the voice's native character. | |
| style | number | 0 – 1. Accepted; the signature style is always present. | |
| speed | number | 0.5 – 2.0. 1.0 is default. | |
| use_speaker_boost | boolean | Accepted for compatibility. |
Response · 200
Binary audio. Content-Type matches the requested format. Response headers: X-Request-Id (trace id), X-Duration (exact audio-seconds billed).
curl -X POST "https://api.secretvoice.dev/v1/text-to-speech/whisper?output_format=mp3_44100_128" \ -H "xi-api-key: $SECRETVOICE_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "text": "Lean in. I have something to tell you.", "model_id": "secret-v1", "language_code": "en", "voice_settings": { "stability": 0.6, "speed": 0.95 } }' \ --output whisper.mp3
Output formats
| Format | Sample rates | Notes |
|---|---|---|
| mp3_* | 22050 · 24000 · 44100 | Bitrates 32 – 192 kbps. Default mp3_44100_128. |
| wav_* | 8000 – 44100 | Uncompressed, highest fidelity. |
| pcm_* | 8000 – 48000 | Raw 16-bit PCM, for realtime pipelines. |
| opus_48000_* | 48000 | Efficient streaming codec. |
| ulaw_8000 / alaw_8000 | 8000 | Telephony codecs, e.g. Twilio. |
Streaming
Audio as it's synthesized.
Identical request to the synchronous endpoint, but the audio streams back as it is produced — ideal for agents and long-form narration that want the first byte fast.
| Parameter | Type | Required | Description |
|---|---|---|---|
| output_format | string | Default mp3_44100_128. |
Request body
Identical to Text to Speech — text, model_id, language_code, voice_settings.
curl -X POST "https://api.secretvoice.dev/v1/text-to-speech/velvet/stream" \ -H "xi-api-key: $SECRETVOICE_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "text": "There you are. I was starting to miss you.", "model_id": "secret-v1" }' \ --output live.mp3
Realtime
A voice agent that responds immediately.
Realtime speech over WebSocket — the protocol voice agents and AI companions use. Send text chunks as they arrive; audio comes back as it's spoken, with word timing preserved for captions.
Send
| Message | Purpose |
|---|---|
| { "text": " " } | Initialize the connection (blank space). May carry voice_settings. |
| { "text": "..." } | Stream text chunks as they become available. |
| { "flush": true } | Force generation of remaining buffered text. |
| { "text": "" } | Close the stream cleanly. |
Receive
| Message | Meaning |
|---|---|
| { "audio": "<base64>", "isFinal": false } | One chunk of generated audio. |
| { "isFinal": true } | The stream is complete. |
| { "error": "..." } | Synthesis failed; the server closes. |
const ws = new WebSocket( "wss://ws.secretvoice.dev/v1/text-to-speech/velvet/stream-input?output_format=mp3_44100_128", { headers: { "xi-api-key": "YOUR_KEY" } } ); ws.onopen = () => { ws.send(JSON.stringify({ text: " " })); ws.send(JSON.stringify({ text: "There you are. I was starting to miss you." })); ws.send(JSON.stringify({ flush: true })); ws.send(JSON.stringify({ text: "" })); }; ws.onmessage = (e) => { const msg = JSON.parse(e.data); if (msg.audio) playBase64Audio(msg.audio); // decode + queue if (msg.isFinal) ws.close(); };
Hear it. The sample below is a real streamed reply generated through the realtime path.
History
Every generation, retrievable.
Generations are stored on your account so you can re-fetch, review, or delete them. Pass ?enable_logging=false on any synthesis call to opt out (zero retention).
Response · 200
{
"history": [{
"history_item_id": "req_01HZxK…",
"voice_id": "velvet",
"text": "Come closer. Let me tell you a secret.",
"date_unix": 1770000000,
"seconds": 8.3
}]
}
Account & Billing
Pay for what you produce.
You are billed per audio-second of produced content. Your balance is deducted progressively during generation, and you can monitor it at any time.
Response · 200
{
"id": "usr_01HZxK…",
"email": "you@example.com",
"is_new_user": false,
"subscription": { "tier": "pay_as_you_go" }
}
Response · 200
{
"tier": "pay_as_you_go",
"character_count": 4123, // audio-seconds used (field name kept for compat)
"character_limit": -1,
"next_character_count_reset_unix": 0
}
Multilingual
One voice, twenty-one languages.
Pass a language_code and the same voice keeps its warmth and character in that language. Supported codes:
en · es · de · fr · it · pt · ru · zh · ja · ko · th · id · vi · ms · nl · pl · et · fi · hi · ta · cs
curl -X POST "https://api.secretvoice.dev/v1/text-to-speech/whisper" \ -H "xi-api-key: $SECRETVOICE_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "text": "もっと近くに来て。秘密を教えてあげる。", "language_code": "ja", "model_id": "secret-v1" }' \ --output whisper-ja.mp3
Rate Limits
Fair use, for everyone.
Limits protect the reliability of the Service for all users. They scale with your plan.
| Limit | Default | Notes |
|---|---|---|
| Requests per minute | 60 | Per API key, per endpoint. |
| Concurrent streams | 5 | Across the streaming and realtime endpoints. |
| Max text length | 5,000 chars | Per synthesis request. Split longer text into consecutive calls with previous_text. |
| Max audio duration | 90 min | Per generation. |
When a limit is exceeded, the API returns 429 with a Retry-After header. Back off and retry after the indicated delay; exponential backoff is recommended.
Errors
Errors you can read.
All errors use a consistent, machine-readable body: {"detail": "..."}.
| Status | Meaning | Example detail |
|---|---|---|
| 400 | Invalid request | "text is required" |
| 401 | Missing or invalid key | "Invalid API key" |
| 402 | Insufficient balance | "No minutes available" |
| 404 | Voice or model not found | "Voice not found" |
| 422 | Validation error | {"detail": [...]} |
| 429 | Rate limit exceeded | "Rate limit exceeded" |
| 500 | Internal error | "TTS generation failed" |
| 501 | Not implemented | "Voice conversion is not available" |
Compatibility
Drop-in for the ElevenLabs protocol.
SecretVoice speaks the ElevenLabs API contract. If your code already talks to ElevenLabs, you can point it at SecretVoice by changing the base URL and using a SecretVoice API key — no code changes.
- Same surface — paths, methods, request bodies, and response shapes follow the same contract.
- Same auth header — xi-api-key is accepted natively.
- Same realtime protocol — the WebSocket stream-input flow matches message-for-message.
- Model aliases — common model identifiers map to secret-v1 automatically.
- Safe over-acceptance — optional fields with no equivalent here are accepted and safely ignored, so clients never break.
- Same error shape — {"detail": "..."} bodies and matching status codes.
Honesty in compatibility. The contract is compatible; the model is ours. A handful of optional parameters (e.g. seed, request stitching ids) are accepted and safely ignored. Features we don't offer (voice conversion, custom voice cloning in v1) return a clear 501 — never a silent success.
Machine-readable
OpenAPI & llms.txt
The API is fully described as machine-readable artifacts, kept in sync with these docs.
- /openapi.json — the complete OpenAPI 3 specification.
- /llms.txt — the API index for AI agents.
- /llms-full.txt — the full reference for AI agents.