API Reference
The TTSBuddy API lets you convert text to speech programmatically. Use it from CLI tools, scripts, AI agents, or any HTTP client.
Base URL
https://ttsbuddy.com/v1/agent-tts
Authentication
All requests require an API key in the Authorization header:
Authorization: Bearer ttsb_<public_id>_<secret>
Create API keys in your TTSBuddy dashboard under Settings. See the API Keys guide for details.
Endpoints
POST — Submit TTS Request
Submit text for conversion. Short texts may complete inline (~10s); longer texts return a job ID for polling.
Headers:
| Header | Required | Value |
|---|---|---|
Authorization | Yes | Bearer ttsb_... |
Content-Type | Yes | application/json |
Idempotency-Key | Recommended | Client-provided key for safe retries |
User-Agent | Recommended | Your app name and version |
Request body:
{
"text": "Text to convert to speech.",
"voice": "af_heart",
"speed": 1.0
}
| Field | Type | Required | Default | Constraints |
|---|---|---|---|---|
text | string | Yes | — | 1–500,000 characters |
voice | string | No | af_heart | Valid voice ID (see Available Voices) |
speed | number | No | 1.0 | 0.5–1.5 (fast voices auto-capped at 1.0) |
Response — 200 Completed:
{
"success": true,
"status": "completed",
"job_id": "550e8400-e29b-41d4-a716-446655440000",
"audio_url": "https://...s3.amazonaws.com/pro/abc123.mp3",
"audio": {
"duration_seconds": 45.2,
"format": "mp3",
"voice": "af_heart",
"speed": 1.0
},
"billing": {
"mode": "subscription",
"estimated_cost_cents": 0,
"monthly_minutes_used": 12.5,
"monthly_minutes_limit": 60,
"monthly_minutes_remaining": 47.5
},
"meta": {
"request_id": "uuid",
"processing_time_ms": 8432,
"api_version": "2026-04"
}
}
Completed responses always include audio and billing objects. Within audio, duration_seconds is optional; expires_at and file_size_bytes are omitted for new API jobs.
Response — 202 Processing:
Returned when the job doesn't complete within the inline wait budget (~10s):
{
"success": true,
"status": "processing",
"job_id": "uuid",
"status_url": "/v1/agent-tts?id=<job_id>",
"retry_after_seconds": 5,
"meta": {
"request_id": "uuid",
"api_version": "2026-04"
}
}
Poll the status_url (resolve against the base URL) until the job completes.
GET — Check Job Status
GET /v1/agent-tts?id=<job_id>
Returns 200 for all known jobs with a structured status body:
| Status | Meaning |
|---|---|
completed | Audio ready — includes audio_url and metadata |
processing | Still generating — includes retry_after_seconds |
failed | Generation failed — includes error details |
expired | Legacy only: persisted audio file was deleted |
Returns 404 for unknown job IDs or jobs belonging to another user.
Error Codes
| Code | HTTP | Description | Suggested Action |
|---|---|---|---|
INVALID_KEY | 401 | Bad, expired, or revoked API key | Check key or create a new one |
INACTIVE_SUBSCRIPTION | 403 | Subscription not active | Reactivate at /billing |
NO_API_ACCESS | 403 | Plan doesn't include API access | Check plan or contact support |
RATE_LIMITED | 429 | Too many requests (POST: 1/min, GET: 30/min) | Wait Retry-After seconds |
USAGE_LIMIT_EXCEEDED | 403 | Monthly TTS minutes exhausted | Upgrade plan or wait for reset |
INVALID_REQUEST | 400 | Missing or invalid fields | Check request body |
TEXT_TOO_LONG | 400 | Exceeds 500,000 characters | Split text into smaller chunks |
NOT_FOUND | 404 | Unknown job ID | Check the job ID |
FILE_EXPIRED | 200 | Legacy: persisted audio deleted | Submit a new request |
TTS_PROVIDER_ERROR | 502 | Upstream TTS service error | Retry with backoff |
INTERNAL_ERROR | 500 | Server error | Retry with backoff |
Error response format:
{
"success": false,
"error": {
"code": "USAGE_LIMIT_EXCEEDED",
"message": "Monthly TTS minutes limit reached",
"details": {
"limit": 60,
"used": 60,
"tier": "pro",
"upgrade_url": "https://ttsbuddy.com/billing"
}
},
"meta": { "request_id": "uuid", "api_version": "2026-04" }
}
Rate Limits & Quotas
| Limit | Value |
|---|---|
| POST requests per minute | 1 per API key |
| GET requests per minute | 30 per API key |
| Max text length | 500,000 characters per request |
| Monthly TTS minutes | Depends on plan |
| Active API keys | 1 per user |
| Audio URL lifetime | Temporary — download immediately after completion |
POST and GET have separate rate-limit buckets — polling for job status does not consume your submission quota. When rate limited, the response includes a Retry-After header with the number of seconds to wait.
Browser CORS
The API uses first-party origin-aware CORS. Requests from ttsbuddy.com and Vercel preview deployments are allowed. Non-browser clients (curl, server-side SDKs) are unaffected.
Idempotency
Send an Idempotency-Key header to make requests safely retryable:
Idempotency-Key: my-unique-request-id
How it works:
- Same key submitted twice returns the existing job — no double charge
- Different key creates a new job
- Keys are scoped per user — different users won't collide
Retry rules:
- Network/transport failures: Retry with the same key (safe)
- Error message says "Use a new Idempotency-Key": The provider accepted the job but it failed downstream — generate a fresh key before retrying
- Other errors: Retry with the same key
For file inputs, hash the content + voice + speed to generate a deterministic key. For stdin, use a random UUID.
Available Voices
The API accepts any voice ID matching the standard pattern (e.g., af_heart, st_m1, bf_emma). Here are the curated voices with stable support:
Flash Voices (Recommended)
Flash voices generate 5-10x faster than standard voices with excellent quality. For API and CLI workflows — especially automation, pipelines, and AI agents — we strongly recommend using Flash voices for the best speed-to-quality ratio.
| ID | Name | Gender | Speed |
|---|---|---|---|
st_f1 | Felicity | Female | Ultra-fast |
st_f2 | Fiona | Female | Ultra-fast |
st_m1 | Marcus | Male | Ultra-fast |
st_m2 | Michael | Male | Ultra-fast |
English (Standard)
| ID | Gender | Accent |
|---|---|---|
af_heart | Female | American (default) |
af_bella | Female | American |
af_nicole | Female | American |
af_sarah | Female | American |
af_alloy | Female | American |
am_michael | Male | American |
am_adam | Male | American |
am_echo | Male | American |
bf_emma | Female | British |
bm_george | Male | British |
Other Languages
| ID | Gender | Language |
|---|---|---|
ef_sofia | Female | Spanish |
em_diego | Male | Spanish |
ff_claire | Female | French |
fm_antoine | Male | French |
hf_priya | Female | Hindi |
hm_raj | Male | Hindi |
if_lucia | Female | Italian |
im_marco | Male | Italian |
jf_yuki | Female | Japanese |
jm_takeshi | Male | Japanese |
pf_ana | Female | Portuguese |
pm_carlos | Male | Portuguese |
zf_mei | Female | Chinese |
zm_chen | Male | Chinese |
The full voice catalog (58+ voices) is available at GET https://tts.api.prod.ttsbuddy.website/api/v1/voices — this is a public endpoint requiring no authentication.
MCP Integration
The API is compatible with AI agent tool-use patterns. Here's an MCP tool definition:
{
"name": "ttsbuddy_speak",
"description": "Convert text to speech audio using TTSBuddy",
"parameters": {
"type": "object",
"properties": {
"text": { "type": "string", "description": "Text to convert (max 500k chars)" },
"voice": { "type": "string", "description": "Voice ID", "default": "af_heart" },
"speed": { "type": "number", "description": "Playback speed 0.5-1.5", "default": 1.0 }
},
"required": ["text"]
}
}
Agent workflow:
- POST with text → if 200, return
audio_url - If 202, poll GET until completed → return
audio_url - On error, return the structured error message