API Documentation
Generate speech, manage voices, and track usage programmatically.
Quick Start
- 1. Create an API key in the Developers dashboard
- 2. List voices to find a voice ID
- 3. Send a POST request to generate speech
- 4. Poll the generation endpoint until complete
Base URL
https://elocute-api.onrender.com/v1Response Format
All responses are returned in JSON format.
// Success
{
"id": "generation-uuid",
"status": "processing"
}
// Error
{
"error": "error_code",
"message": "Human readable error message"
}Authentication
All API requests require an API key. Create one in the Developers dashboard.
X-API-Key header (recommended)
X-API-Key: sk_live_your_api_key_hereAuthorization header
Authorization: Bearer sk_live_your_api_key_hereKeep your keys secure
Never expose API keys in client-side code or public repositories. If a key is compromised, revoke it immediately from the dashboard.
Endpoints
/v1/ttsGenerate speech from text using a specified voice.
Request Body
textrequiredText to convert to speech (max 40,000 characters)
voice_idrequiredUUID of the voice to use
Response
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"status": "processing"
}/v1/generations/:idCheck the status of a generation request.
Response
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"status": "completed",
"audio_url": "https://cdn.elocute.net/audio/example.wav",
"audio_duration": 5.2,
"char_count": 100,
"created_at": "2026-01-15T10:30:00Z",
"completed_at": "2026-01-15T10:30:15Z"
}/v1/voicesList all available voices (preset voices and your custom voices).
Response
[
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Rachel",
"description": "American female, warm and friendly",
"voice_type": "preset",
"category": "American",
"preview_url": "https://cdn.elocute.net/presets/preview.wav"
}
]/v1/voices/:idGet details for a specific voice.
Response
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Rachel",
"description": "American female, warm and friendly",
"voice_type": "preset",
"category": "American",
"preview_url": "https://cdn.elocute.net/presets/preview.wav"
}/v1/usageGet your current usage statistics.
Response
{
"chars_used_this_month": 500,
"monthly_char_limit": 100000,
"percentage_used": 0.5,
"subscription_tier": "pro"
}Code Examples
cURL
# Generate speech
curl -X POST https://elocute-api.onrender.com/v1/tts \
-H "X-API-Key: sk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"text": "Hello, world! This is a test.",
"voice_id": "550e8400-e29b-41d4-a716-446655440000"
}'
# Check generation status
curl https://elocute-api.onrender.com/v1/generations/GENERATION_ID \
-H "X-API-Key: sk_live_your_api_key"
# List voices
curl https://elocute-api.onrender.com/v1/voices \
-H "X-API-Key: sk_live_your_api_key"Python
import requests
import time
API_KEY = "sk_live_your_api_key"
BASE_URL = "https://elocute-api.onrender.com/v1"
headers = {
"X-API-Key": API_KEY,
"Content-Type": "application/json"
}
# List available voices
voices = requests.get(f"{BASE_URL}/voices", headers=headers).json()
print(f"Found {len(voices)} voices")
# Generate speech
response = requests.post(
f"{BASE_URL}/tts",
headers=headers,
json={
"text": "Hello, world! This is a test.",
"voice_id": voices[0]["id"]
}
)
generation = response.json()
print(f"Generation started: {generation['id']}")
# Poll for completion
while True:
status = requests.get(
f"{BASE_URL}/generations/{generation['id']}",
headers=headers
).json()
if status["status"] == "completed":
print(f"Audio URL: {status['audio_url']}")
break
elif status["status"] == "failed":
print(f"Error: {status.get('error_message')}")
break
time.sleep(2)JavaScript / TypeScript
const API_KEY = "sk_live_your_api_key";
const BASE_URL = "https://elocute-api.onrender.com/v1";
const headers = {
"X-API-Key": API_KEY,
"Content-Type": "application/json"
};
// List available voices
async function listVoices() {
const response = await fetch(`${BASE_URL}/voices`, { headers });
return response.json();
}
// Generate speech
async function generateSpeech(text: string, voiceId: string) {
const response = await fetch(`${BASE_URL}/tts`, {
method: "POST",
headers,
body: JSON.stringify({ text, voice_id: voiceId })
});
return response.json();
}
// Check generation status
async function getGeneration(id: string) {
const response = await fetch(`${BASE_URL}/generations/${id}`, { headers });
return response.json();
}
// Example usage
async function main() {
const voices = await listVoices();
console.log(`Found ${voices.length} voices`);
const generation = await generateSpeech(
"Hello, world! This is a test.",
voices[0].id
);
console.log(`Generation started: ${generation.id}`);
// Poll for completion
let status;
do {
await new Promise(r => setTimeout(r, 2000));
status = await getGeneration(generation.id);
} while (status.status === "processing");
if (status.status === "completed") {
console.log(`Audio URL: ${status.audio_url}`);
}
}
main();Rate Limits
API requests are rate limited based on your subscription tier.
| Tier | Requests / min | Monthly Credits |
|---|---|---|
| Free | — | 10,000 |
| Pro | 60 | 100,000 |
| Business | 150 | 500,000 |
Rate Limit Headers
All responses include rate limit information:
X-RateLimit-LimitMaximum requests per minuteX-RateLimit-RemainingRequests remaining in current windowX-RateLimit-ResetSeconds until the rate limit resetsRate limit exceeded
If you exceed the rate limit, you'll receive a 429 response with a Retry-After header indicating when you can retry.
Error Codes
The API uses standard HTTP status codes and returns detailed error information.
| Code | Error |
|---|---|
| 400 | bad_request |
| 401 | unauthorized |
| 401 | invalid_api_key |
| 401 | revoked_api_key |
| 402 | usage_limit_exceeded |
| 403 | voice_access_denied |
| 404 | voice_not_found |
| 404 | generation_not_found |
| 429 | rate_limit_exceeded |
| 500 | internal_error |
Error Response Format
{
"error": "voice_not_found",
"message": "Voice with ID '550e8400-e29b-41d4-a716-446655440000' not found."
}