curl --request POST \
--url https://api.ekly.ai/v1/audio \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"model": "eleven_multilingual_v2",
"text": "Welcome back. Your export is ready.",
"voice_name": "Rachel"
}
'import requests
url = "https://api.ekly.ai/v1/audio"
payload = {
"model": "eleven_multilingual_v2",
"text": "Welcome back. Your export is ready.",
"voice_name": "Rachel"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
model: 'eleven_multilingual_v2',
text: 'Welcome back. Your export is ready.',
voice_name: 'Rachel'
})
};
fetch('https://api.ekly.ai/v1/audio', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.ekly.ai/v1/audio",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'model' => 'eleven_multilingual_v2',
'text' => 'Welcome back. Your export is ready.',
'voice_name' => 'Rachel'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.ekly.ai/v1/audio"
payload := strings.NewReader("{\n \"model\": \"eleven_multilingual_v2\",\n \"text\": \"Welcome back. Your export is ready.\",\n \"voice_name\": \"Rachel\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.ekly.ai/v1/audio")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"model\": \"eleven_multilingual_v2\",\n \"text\": \"Welcome back. Your export is ready.\",\n \"voice_name\": \"Rachel\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.ekly.ai/v1/audio")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"model\": \"eleven_multilingual_v2\",\n \"text\": \"Welcome back. Your export is ready.\",\n \"voice_name\": \"Rachel\"\n}"
response = http.request(request)
puts response.read_body{
"created_at": "2023-11-07T05:31:56Z",
"id": "6f1c2d3e-9a0b-4c7d-8e1f-2a3b4c5d6e7f",
"model": "seedance-2-5-fal",
"prompt": "<string>",
"status": "pending",
"type": "image",
"completed_at": "2023-11-07T05:31:56Z",
"credits_charged": 123,
"error": {
"code": "<string>",
"message": "<string>"
},
"idempotency_key": "<string>",
"outputs": [
{
"url": "<string>",
"asset_id": "<string>",
"content_type": "video/mp4",
"duration_seconds": 123,
"height": 123,
"width": 123
}
]
}{
"error": {
"code": "unauthenticated",
"message": "This API key is not valid. Create a new one in Settings → Team.",
"trace_id": "c3746d5302dc4be6b2e8fa99fa762a8c"
}
}{
"error": {
"code": "payment_required",
"message": "Insufficient credits: this generation needs 39.6 credits and 12.0 are available.",
"trace_id": "c3746d5302dc4be6b2e8fa99fa762a8c"
}
}{
"error": {
"code": "forbidden",
"message": "API keys can only call the /v1 API.",
"trace_id": "c3746d5302dc4be6b2e8fa99fa762a8c"
}
}{
"error": {
"code": "conflict",
"message": "This idempotency key was already used with a different request.",
"trace_id": "c3746d5302dc4be6b2e8fa99fa762a8c"
}
}{
"error": {
"code": "validation_error",
"details": [
{
"loc": [
"body",
"model"
],
"msg": "Field required",
"type": "missing"
}
],
"message": "Request validation failed.",
"trace_id": "c3746d5302dc4be6b2e8fa99fa762a8c"
}
}{
"error": {
"code": "rate_limited",
"message": "Rate limit exceeded; retry after 12s.",
"trace_id": "c3746d5302dc4be6b2e8fa99fa762a8c"
}
}Generate speech or music
Submits a speech or music generation; the model decides which. Returns immediately with status: pending; credits are reserved now and settled when the job finishes. Poll GET /v1/generations/{id} until completed or failed.
curl --request POST \
--url https://api.ekly.ai/v1/audio \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"model": "eleven_multilingual_v2",
"text": "Welcome back. Your export is ready.",
"voice_name": "Rachel"
}
'import requests
url = "https://api.ekly.ai/v1/audio"
payload = {
"model": "eleven_multilingual_v2",
"text": "Welcome back. Your export is ready.",
"voice_name": "Rachel"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
model: 'eleven_multilingual_v2',
text: 'Welcome back. Your export is ready.',
voice_name: 'Rachel'
})
};
fetch('https://api.ekly.ai/v1/audio', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.ekly.ai/v1/audio",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'model' => 'eleven_multilingual_v2',
'text' => 'Welcome back. Your export is ready.',
'voice_name' => 'Rachel'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.ekly.ai/v1/audio"
payload := strings.NewReader("{\n \"model\": \"eleven_multilingual_v2\",\n \"text\": \"Welcome back. Your export is ready.\",\n \"voice_name\": \"Rachel\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.ekly.ai/v1/audio")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"model\": \"eleven_multilingual_v2\",\n \"text\": \"Welcome back. Your export is ready.\",\n \"voice_name\": \"Rachel\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.ekly.ai/v1/audio")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"model\": \"eleven_multilingual_v2\",\n \"text\": \"Welcome back. Your export is ready.\",\n \"voice_name\": \"Rachel\"\n}"
response = http.request(request)
puts response.read_body{
"created_at": "2023-11-07T05:31:56Z",
"id": "6f1c2d3e-9a0b-4c7d-8e1f-2a3b4c5d6e7f",
"model": "seedance-2-5-fal",
"prompt": "<string>",
"status": "pending",
"type": "image",
"completed_at": "2023-11-07T05:31:56Z",
"credits_charged": 123,
"error": {
"code": "<string>",
"message": "<string>"
},
"idempotency_key": "<string>",
"outputs": [
{
"url": "<string>",
"asset_id": "<string>",
"content_type": "video/mp4",
"duration_seconds": 123,
"height": 123,
"width": 123
}
]
}{
"error": {
"code": "unauthenticated",
"message": "This API key is not valid. Create a new one in Settings → Team.",
"trace_id": "c3746d5302dc4be6b2e8fa99fa762a8c"
}
}{
"error": {
"code": "payment_required",
"message": "Insufficient credits: this generation needs 39.6 credits and 12.0 are available.",
"trace_id": "c3746d5302dc4be6b2e8fa99fa762a8c"
}
}{
"error": {
"code": "forbidden",
"message": "API keys can only call the /v1 API.",
"trace_id": "c3746d5302dc4be6b2e8fa99fa762a8c"
}
}{
"error": {
"code": "conflict",
"message": "This idempotency key was already used with a different request.",
"trace_id": "c3746d5302dc4be6b2e8fa99fa762a8c"
}
}{
"error": {
"code": "validation_error",
"details": [
{
"loc": [
"body",
"model"
],
"msg": "Field required",
"type": "missing"
}
],
"message": "Request validation failed.",
"trace_id": "c3746d5302dc4be6b2e8fa99fa762a8c"
}
}{
"error": {
"code": "rate_limited",
"message": "Rate limit exceeded; retry after 12s.",
"trace_id": "c3746d5302dc4be6b2e8fa99fa762a8c"
}
}Authorizations
An organization API key created in Settings → Team, sent as Authorization: Bearer <key>.
Headers
Reuse the same value when retrying the same request; a repeat returns the original generation without charging again. Reusing it with a different body returns 409.
128Body
Generate speech or music; the model decides which.
Text normalization: on/off/auto
Optional BPM override (60-200). If not provided, tempo is used to estimate. (music generation only)
60 <= x <= 200ElevenLabs MusicPrompt composition plan. Mutually exclusive with prompt/prompt_tags; section durations control track length.
Content type preset name
Duration in seconds. Lyria allows 5-30 (validated per-model in the route); ElevenLabs Music allows up to 300. Not used for TTS.
3 <= x <= 600Energy level: 'low', 'medium', or 'high' (music generation only)
Generate instrumental-only music (ElevenLabs Music, prompt mode only)
Client-supplied key (≤128 chars); a repeat with the same key returns the original generation without re-charging
128Generate instrumental-only music with no vocals (Lyria 3 only). Mutually exclusive with lyrics.
Language for TTS synthesis: Qwen3 uses names such as 'Auto', 'English', 'Chinese'; Gemini uses BCP-47 codes. ElevenLabs auto-detects language and ignores this shared field.
Custom lyrics for vocal generation (Lyria 3 only). Use [Verse], [Chorus], [Bridge] markers. Pro model also supports [MM:SS] timestamps.
Audio model identifier. Music: 'models/lyria-realtime-exp'. TTS Gemini: 'gemini-3.1-flash-tts-preview'. TTS ElevenLabs: 'eleven_v4', 'eleven_v3', 'eleven_multilingual_v2', 'eleven_turbo_v2_5'
What to avoid in the music (Lyria 2 only). Ignored by Lyria RealTime.
Generation ID for next audio context
'text' or 'audio'
ElevenLabs request IDs for next audio
Next text context (not spoken)
ElevenLabs MP3 or WAV output format (e.g. mp3_44100_128, wav_24000)
Generation ID for previous audio context
'text' or 'audio'
ElevenLabs request IDs for previous audio
Previous text context (not spoken)
Project scope for the generated asset (optional)
Free-text music prompt (ElevenLabs Music). Mutually exclusive with composition_plan.
List of prompt tags describing the desired music (e.g. ['energetic', 'rock', 'guitar']). Required for music generation.
Dictionary entry IDs to apply
Qwen3 voice embedding ID (from voice profile clone)
Qwen3 model size
Number of variations per API call (Lyria 2 only, 1-4). Mutually exclusive with seed.
1 <= x <= 4Random seed for reproducible output (Lyria 2 only). Mutually exclusive with sample_count > 1.
Multi-speaker script as an ordered list of {voice_name, text} lines. Mutually exclusive with top-level text. ElevenLabs v3 without stitching context and two-voice Gemini conversations use native dialogue; other requests synthesize turns independently. All return one audio file.
Show child attributes
Show child attributes
Voice clarity/similarity for ElevenLabs (0.0-1.0). Higher = closer to original voice.
0 <= x <= 1Speech speed. Per-model range comes from the catalog.
0.7 <= x <= 1.3Voice stability for ElevenLabs (0.0-1.0). Higher = more consistent, lower = more expressive.
0 <= x <= 1Style exaggeration (0.0-1.0)
0 <= x <= 1Optional creativity/randomness (0.0-2.0). Higher = more variation. (music generation only)
0 <= x <= 2Tempo: 'slow', 'medium', or 'fast' (music generation only)
Text to convert to speech. Required for single-speaker TTS. Mutually exclusive with segments.
Human-readable voice name for UI display (voice_name carries the voice_id for backend)
Voice name for TTS. Gemini: 'Zephyr', 'Charon', 'Kore', 'Fenrir', 'Aoede', 'Puck'. ElevenLabs: a current premade name such as 'Sarah', 'George' or 'Laura', or any library voice id.
Voice profile ID (used for Qwen3 cloned voices)
Response
Successful Response
One generation. Poll GET /v1/generations/{id} until status is completed or failed.
"6f1c2d3e-9a0b-4c7d-8e1f-2a3b4c5d6e7f"
"seedance-2-5-fal"
pending, completed, failed image, video, audio Credits actually charged; null while pending.
Show child attributes
Show child attributes
Show child attributes
Show child attributes