eidosSpeech eidosSpeech v3

API Documentation

The eidosSpeech REST API converts text to speech using Microsoft Edge TTS neural voices. Responses are audio (mp3, wav, ogg, flac) or JSON.

Need a quick start? See free text to speech API guide.

Base URL
https://eidosspeech.xyz/api/v1
Response Format
TTS: audio/mpeg|audio/wav|audio/ogg|audio/flac
Errors: application/json
API Version
All endpoints prefixed with /api/v1/

Authentication

eidosSpeech supports two authentication methods. Use your API key for server-side integrations, or JWT tokens for user-facing apps.

X-API-Key Recommended for server-side use
curl -H "X-API-Key: esk_your_api_key_here" ...
Authorization: Bearer For JWT access tokens
curl -H "Authorization: Bearer <access_token>" ...
No Auth Web UI only (anonymous tier)

Anonymous access (from eidosspeech.xyz origin) gets 5 req/day, 500 char limit. No API key needed to use the web UI.

Rate Limits

Tier Requests/Day Chars/Request Requests/Min
Anonymous (Web UI) 5 500 1
Registered (Free) 30 2,000 3

Rate Limit Response Headers

X-RateLimit-Tier: registered
X-RateLimit-Plan: free
X-RateLimit-Limit-Day: 30
X-RateLimit-Remaining-Day: 24
X-RateLimit-Limit-Min: 3
X-RateLimit-Char-Limit: 2000
X-Cache-Hit: false
X-Cache-Status: MISS
X-Cache-Key: 9f0ab5c31c5d1b11

Daily limits reset at 00:00 UTC. Requests for the same identity are serialized and may briefly queue when server slots are full.

POST

/tts

Generate speech from text using 1,200+ neural voices. Supports format selection, style controls, and optional completion webhook callbacks.

Request Body

{
  "text":   "Your text here",      // required, max 2000 chars (registered)
  "voice":  "id-ID-GadisNeural",  // optional, default: id-ID-GadisNeural
  "rate":   "+0%",                 // optional, range: -50% to +100%
  "pitch":  "+0Hz",                // optional, range: -50Hz to +50Hz
  "volume": "+0%",                 // optional, range: -50% to +50%
  "format": "mp3",                 // optional: mp3, wav, ogg, flac
  "bitrate": "128k",               // optional: 64k, 96k, 128k, 192k, 256k, 320k
  "webhook_url": "https://example.com/hook", // optional completion callback
  "webhook_secret": "your-signing-secret",     // optional HMAC signature
  "style":  "cheerful",            // optional, emotion/style (voice-specific)
  "style_degree": 1.0              // optional, style intensity (0.01-2.0)
}

cURL Example

curl -X POST https://eidosspeech.xyz/api/v1/tts \
  -H "X-API-Key: esk_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "text": "Hello, this is a test of the text to speech API.",
    "voice": "en-US-JennyNeural",
    "format": "wav",
    "bitrate": "192k",
    "rate": "+10%",
    "pitch": "+5Hz"
  }' \
  --output audio.wav

Python Example

import requests

response = requests.post(
    "https://eidosspeech.xyz/api/v1/tts",
    headers={"X-API-Key": "esk_your_api_key"},
    json={
        "text": "Halo, selamat datang di eidosSpeech!",
        "voice": "id-ID-GadisNeural",
        "format": "mp3",
        "bitrate": "128k",
        "rate": "+0%"
    }
)

if response.status_code == 200:
    with open("output.mp3", "wb") as f:
        f.write(response.content)
    print(f"Remaining: {response.headers.get('X-RateLimit-Remaining-Day')}")
else:
    print(response.json())

JavaScript Example

const response = await fetch('https://eidosspeech.xyz/api/v1/tts', {
  method: 'POST',
  headers: {
    'X-API-Key': 'esk_your_api_key',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    text: 'Welcome to eidosSpeech API!',
    voice: 'en-US-AriaNeural',
    rate: '+0%',
    pitch: '+0Hz'
  })
});

const audioBlob = await response.blob();
const audioUrl = URL.createObjectURL(audioBlob);
const audio = new Audio(audioUrl);
audio.play();

Response & Errors

✓ 200 OK
Content-Type: audio/mpeg
X-RateLimit-Remaining-Day: 29
X-Cache-Hit: false
X-Cache-Status: MISS
X-Cache-Key: 9f0ab5c31c5d1b11

(Audio bytes by requested format)
✕ 400 Bad Request
{
  "error": "ValidationError",
  "message": "Text exceeds 2000 characters"
}
✕ 401 Unauthorized
{
  "error": "AuthenticationError",
  "message": "Invalid or expired API key"
}
✕ 429 Too Many Requests
{
  "error": "RateLimitError",
  "message": "Daily limit reached",
  "detail": { "limit": 30, "used": 30 }
}
Retry-After: 86400
POST

/tts/script

NEW v2.1

Generate multi-voice dialog audio from script. Perfect for podcasts, audiobooks, and conversational content. Registered users only. Returns merged MP3 audio with natural pauses between speakers.

Request Body

{
  "script": "[John]: Hello!\\n[Mary]: Hi there!",  // required, format: [Speaker]: Text
  "voice_map": {                                      // required, speaker → voice mapping
    "John": "en-US-GuyNeural",
    "Mary": "en-US-JennyNeural"
  },
  "pause_ms": 500,                                  // optional, pause between lines (0-2000ms, default: 500)
  "rate": "+0%",                                     // optional, speech rate (-50% to +100%)
  "pitch": "+0Hz",                                    // optional, pitch adjustment (-50Hz to +50Hz)
  "volume": "+0%"                                    // optional, volume level (-50% to +50%)
}

Script Format

Each line must follow the format: [SpeakerName]: Dialog text

[John]: Hello, how are you today?
[Mary]: I'm doing great, thanks for asking!
[John]: That's wonderful to hear.
[Mary]: How about you?
Rules:
  • Speaker names are case-sensitive and must match voice_map keys
  • Each speaker must have a corresponding voice in voice_map
  • Empty lines are ignored
  • Lines without [Speaker]: format will cause validation error

cURL Example

curl -X POST https://eidosspeech.xyz/api/v1/tts/script \
  -H "X-API-Key: esk_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "script": "[Host]: Welcome to our podcast!\\n[Guest]: Thanks for having me!",
    "voice_map": {
      "Host": "en-US-GuyNeural",
      "Guest": "en-US-JennyNeural"
    },
    "pause_ms": 800
  }' \
  --output podcast.mp3

Python Example

import requests

script = """[Narrator]: Once upon a time...
[Character1]: Hello there!
[Character2]: Hi! How are you?"""

response = requests.post(
    "https://eidosspeech.xyz/api/v1/tts/script",
    headers={"X-API-Key": "esk_your_api_key"},
    json={
        "script": script,
        "voice_map": {
            "Narrator": "en-US-AriaNeural",
            "Character1": "en-US-GuyNeural",
            "Character2": "en-US-JennyNeural"
        },
        "pause_ms": 600
    }
)

if response.status_code == 200:
    with open("output.mp3", "wb") as f:
        f.write(response.content)
else:
    print(response.json())

JavaScript Example

const script = `[Host]: Welcome to the show!
[Guest]: Thank you for having me!
[Host]: Let's dive right in.`;

const response = await fetch('https://eidosspeech.xyz/api/v1/tts/script', {
  method: 'POST',
  headers: {
    'X-API-Key': 'esk_your_api_key',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    script: script,
    voice_map: {
      'Host': 'en-US-GuyNeural',
      'Guest': 'en-US-JennyNeural'
    },
    pause_ms: 700
  })
});

const audioBlob = await response.blob();
const audioUrl = URL.createObjectURL(audioBlob);
const audio = new Audio(audioUrl);
audio.play();

Response & Errors

✓ 200 OK
Content-Type: audio/mpeg
X-RateLimit-Remaining-Day: 9

(Merged MP3 audio bytes)
✕ 400 Bad Request
{
  "error": "ValidationError",
  "message": "Speaker 'John' not found in voice_map"
}
✕ 403 Forbidden
{
  "error": "ForbiddenError",
  "message": "Multi-voice requires registration"
}
✕ 429 Too Many Requests
{
  "error": "RateLimitError",
  "message": "Daily limit reached (10/day)"
}
Retry-After: 43200

Rate Limits & Best Practices

  • Registered users: 10 requests/day, 2 requests/minute
  • Character count includes all dialog text (excluding speaker names)
  • Recommended pause_ms: 500-800ms for natural conversation
  • Use consistent voice genders for better audio quality
  • Test with short scripts first before generating long content
POST

/tts/subtitle

NEW v2.1

Generate speech with subtitle file (.srt). Returns JSON with audio URL and SRT content.

Request Body

{
  "text":  "Your text here",
  "voice": "id-ID-GadisNeural"  // optional
}

Response

{
  "audio_url": "/cache/abc123.mp3",
  "subtitle": "1\\n00:00:00,000 --> 00:00:02,500\\nYour text here\\n"
}
POST

/tts/translate

NEW

Translate source text then generate speech in the target language. Supports all standard TTS fields.

{
  "text": "Hello world",
  "source_lang": "en",
  "target_lang": "id",
  "voice": "id-ID-GadisNeural",
  "format": "mp3"
}
POST

/tts/ssml

v3

Render a safe subset of SSML to a single MP3. Supported tags: <break> (real silence), <prosody> (rate/pitch/volume), <emphasis>, and <sub> (pronunciation). Unsupported tags (incl. Azure mstts:express-as) are ignored — markup is never read aloud. Billed by spoken character count.

Request Body

{
  "ssml": "<speak>Hi<break time=\"500ms\"/> welcome to <sub alias=\"eye-doss speech\">eidosSpeech</sub>.</speak>",
  "voice": "en-US-JennyNeural"
}

Response

Content-Type: audio/mpeg   →   single stitched MP3
POST

/tts/long

v3

Synthesize text that exceeds the single-request character limit. The text is split at sentence boundaries (Latin & CJK aware), each chunk is synthesized, and the audio is stitched into one MP3. Counts as one request; total characters must fit char_limit × chunk_count (max 12 chunks). Response header X-Chunks reports the chunk count.

Request Body

{
  "text": "A very long article… multiple paragraphs…",
  "voice": "en-US-JennyNeural",
  "rate": "+0%",
  "pitch": "+0Hz",
  "volume": "+0%"
}

Response

Content-Type: audio/mpeg
X-Chunks: 5   →   single stitched MP3
POST

/tts/from-srt

NEW

Upload an SRT file and return merged timeline audio. Request uses multipart/form-data.

curl -X POST https://eidosspeech.xyz/api/v1/tts/from-srt \
  -H "X-API-Key: esk_your_api_key_here" \
  -F "srt_file=@subtitle.srt" \
  -F "voice=id-ID-GadisNeural" \
  -F "format=mp3" \
  -o dubbed.mp3
POST

/batch/tts

NEW

Process multiple TTS requests in one call. Response is a ZIP archive with generated audio files and a manifest.json that includes per-item status.

Request Body

{
  "requests": [
    { "text": "Halo", "voice": "id-ID-GadisNeural", "format": "mp3" },
    { "text": "Hello", "voice": "en-US-JennyNeural", "format": "wav", "bitrate": "192k" }
  ]
}

Response

Content-Type: application/zip
X-Batch-Total: 2
X-Batch-Success: 2
X-Batch-Failed: 0

tts_batch.zip
  ├── manifest.json
  ├── 001_id-ID-GadisNeural.mp3
  └── 002_en-US-JennyNeural.wav
GET

/queue/status

NEW

View current processing load and estimated wait time for TTS queue.

{
  "available_slots": 1,
  "max_slots": 3,
  "queued_requests": 2,
  "current_load": "67%",
  "estimated_wait": "5-15 seconds",
  "details": {
    "tts": {
      "available_slots": 1,
      "max_slots": 3,
      "in_use": 2,
      "queued_requests": 2,
      "current_load_pct": 66.7,
      "priority_lane": { "available_slots": 1, "max_slots": 1, "in_use": 0 }
    }
  }
}
GET

/voices

List all available TTS voices. Public endpoint — no authentication.

Query Parameters

language Filter by language code: id-ID, en-US
gender Filter by gender: Male or Female
search Search voice name or language
GET /api/v1/voices?language=id-ID&gender=Female

{
  "voices": [
    { "id": "id-ID-GadisNeural", "name": "Gadis", "language": "Bahasa Indonesia", "gender": "Female" },
    { "id": "id-ID-ArdiNeural", "name": "Ardi", "language": "Bahasa Indonesia", "gender": "Male" }
  ],
  "total": 2
}
GET

/health

Returns service health including database status, cache stats, queue load, and proxy state.

{
  "status": "ok",
  "db": "ok",
  "cache": { "files": 340, "hit_rate_pct": 64.2 },
  "queue": { "tts": { "available_slots": 2, "max_slots": 3 } }
}

Auth Endpoints

Main authentication endpoints are available under /api/v1/auth:

POST /auth/register
POST /auth/login
POST /auth/refresh
POST /auth/logout
GET  /auth/me
GET

/analytics

NEW

User analytics dashboard endpoint. Requires authenticated user token.

GET /api/v1/analytics?period=30d

{
  "period": "30d",
  "plan": "free",
  "requests_chart": [{ "date": "2026-03-01", "requests": 3, "chars": 420 }],
  "most_used_voices": [{ "voice": "id-ID-GadisNeural", "count": 12 }],
  "peak_hours": [{ "hour": "14", "activity": 8 }],
  "avg_chars_per_request": 390.5,
  "cache_hit_rate": "62.4%",
  "cost_projection": "$0 (free/included tier)"
}

Team Collaboration Endpoints

POST   /api/v1/teams
GET    /api/v1/teams
GET    /api/v1/teams/{team_id}
POST   /api/v1/teams/{team_id}/members
DELETE /api/v1/teams/{team_id}/members/{member_user_id}

Voice Clone Endpoints Experimental

Voice cloning is under active development and currently disabled; these endpoints return 503 Service Unavailable until the training backend ships.

POST /api/v1/voice/clone                 (multipart form upload)
GET  /api/v1/voice/clone/jobs
GET  /api/v1/voice/clone/jobs/{job_id}

Billing & Tier Endpoints

GET    /api/v1/billing/me
POST   /api/v1/billing/byok
DELETE /api/v1/billing/byok
POST   /api/v1/billing/admin/set-tier      (admin key required)
POST   /api/v1/billing/admin/add-credit    (admin key required)

Integration Ecosystem Endpoints

GET /api/v1/integrations
GET /api/v1/integrations/{integration_id}

Developer Experience Endpoints

GET /api/v1/developer/sdk
GET /api/v1/developer/changelog

Error Format

All errors return consistent JSON with error, message, and optional detail.

{
  "error":   "RateLimitError",
  "message": "Daily limit reached (30 requests/day for registered tier).",
  "detail":  { "limit": 30, "used": 30, "retry_after": 86400 }
}
Status Error Type Description
400 ValidationError Bad request data
401 AuthenticationError Invalid or expired token
403 ForbiddenError No auth from external origin
402 PaymentRequired PAYG balance not sufficient for request
409 ConflictError Email already registered
429 RateLimitError Rate limit hit — check Retry-After
503 ServiceUnavailable TTS engine temporarily unavailable

Available Voices by Language

Complete list of 1,200+ voice IDs you can use in the voice parameter. Select a language to see all available voices including multilingual ones.

Loading voices...
👆 Select a language above to view available voices
Or use the search box to find specific voices

Note: All voices are powered by Microsoft Edge TTS Neural technology. Multilingual voices (marked with 🌍) can speak multiple languages with native-like pronunciation. Use the GET /api/v1/voices endpoint to fetch this list programmatically.

About · Terms · Privacy · Contact