Add AI voices to your apps, workflows and automations
A simple REST API for personal projects and businesses. Create keys in your account, send text, get studio-quality audio with subtitles and timings back.
https://cotsiasane.com/wp-json/ai-tts/v1
Authentication
Send your key in the Authorization header:
Authorization: Bearer tts_live_YOUR_KEY
Or use the X-API-Key header. Keep keys on your server. Business keys can be limited to your server IPs and websites, and every key can have a monthly credit cap.
Credits & limits
1 credit = up to 200 characters. API calls use the same credits as the studio. Requests per minute depend on your plan; going over returns HTTP 429.
Endpoints
| POST | /speechGenerate speech (simple or video sync). Returns the audio, SRT / VTT and timeline URLs, or a queued job. |
| GET | /generations/{id}Status and result of a generation (poll queued jobs here). |
| GET | /generationsYour history — page, per_page (max 100). |
| DELETE | /generations/{id}Delete a generation and its files. |
| GET | /voices?language=en-GBVoices available for a language / accent (no key needed). |
| GET | /languagesAll languages and regional accents (no key needed). |
| GET | /accountPlan, credits left and this key's monthly usage. |
Generate speech — POST /speech
curl -X POST https://cotsiasane.com/wp-json/ai-tts/v1/speech \
-H "Authorization: Bearer tts_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"text": "Welcome to our channel! [pause 1s] Let's get started.",
"voice": "openai:coral",
"language": "en-GB",
"tone": "friendly",
"speed": 1.05,
"format": "mp3"
}'
const res = await fetch('https://cotsiasane.com/wp-json/ai-tts/v1/speech', {
method: 'POST',
headers: {
'Authorization': 'Bearer ' + process.env.TTS_API_KEY,
'Content-Type': 'application/json'
},
body: JSON.stringify({ text: 'Hello world', voice: 'openai:marin', language: 'en-US' })
});
const job = await res.json();
console.log(job.audio_url, job.srt_url);
import os, requests
r = requests.post('https://cotsiasane.com/wp-json/ai-tts/v1/speech',
headers={'Authorization': 'Bearer ' + os.environ['TTS_API_KEY']},
json={'text': 'Namaste! Aapka swagat hai.', 'voice': 'openai:coral', 'language': 'hi-IN'})
job = r.json()
print(job['audio_url'])
$res = wp_remote_post( 'https://cotsiasane.com/wp-json/ai-tts/v1/speech', array( 'headers' => array( 'Authorization' => 'Bearer ' . TTS_API_KEY, 'Content-Type' => 'application/json' ), 'body' => wp_json_encode( array( 'text' => 'Hello', 'voice' => 'openai:ash' ) ), 'timeout' => 120, ) ); $job = json_decode( wp_remote_retrieve_body( $res ), true );
Parameters
text | string | The script. Add [pause 1s] or [pause 500ms] for pauses. |
voice | string | Voice id from /voices, e.g. openai:coral, google:en-GB-Neural2-A. Defaults to a good voice for the language. |
language | string | Locale with accent, e.g. en-US, en-IN, hi-IN, fr-CA. Default en-US. |
tone | string | neutral, friendly, cheerful, calm, professional, storytelling, serious, excited, whisper |
speed | number | 0.5 – 2.0 (1 = normal) |
pitch | number | -10 – +10 semitones (0 = normal) |
instructions | string | Optional free-text direction, e.g. "sound like a radio host". |
format | string | mp3 | wav |
title | string | Optional title shown in your history. |
translate | boolean | Translate the text into the language first. |
mode | string | "sync" for video timelines (with segments or srt / vtt). |
segments | array | [{start, end?, text}] — times in seconds or "hh:mm:ss.mmm". |
fit | boolean | Speed lines up to fit their slot (default true). |
async | boolean | Return immediately with status "queued" (long scripts are queued automatically). |
webhook_url | string | Called with the result when the job finishes (signed with your key's webhook secret). |
Response
{
"id": 1842, "status": "done", "voice": "openai:coral", "language": "en-GB",
"characters": 64, "credits": 1, "duration": 4.21, "render_ms": 1380,
"audio_url": "https://…/ai-tts/audio/….mp3",
"srt_url": "https://…/….srt", "vtt_url": "https://…/….vtt", "timeline_url": "https://…/….json",
"status_url": "https://cotsiasane.com/wp-json/ai-tts/v1/generations/1842"
}
Video sync
Send timed lines (or a whole SRT / VTT file). Each line starts exactly at its time and is sped up to fit its slot when needed. You get one WAV the length of your timeline plus captions and a per-line report.
curl -X POST https://cotsiasane.com/wp-json/ai-tts/v1/speech \
-H "Authorization: Bearer tts_live_YOUR_KEY" -H "Content-Type: application/json" \
-d '{
"mode": "sync",
"voice": "openai:onyx",
"fit": true,
"segments": [
{ "start": "00:00:01.000", "end": "00:00:04.000", "text": "Every great story starts with a voice." },
{ "start": 5.5, "text": "Let's make yours." }
]
}'
# or send a subtitle file as text: "srt": "1\n00:00:01,000 --> 00:00:04,000\nHello\n"
Webhooks
Pass webhook_url and we POST the finished generation to it. Check the X-TTS-Signature header with your key's webhook secret (shown next to the key in your account).
// Node / Express: verify the webhook signature
const crypto = require('crypto');
app.post('/tts-webhook', express.raw({ type: 'application/json' }), (req, res) => {
const sig = 'sha256=' + crypto.createHmac('sha256', process.env.TTS_WEBHOOK_SECRET)
.update(req.body).digest('hex');
if (sig !== req.get('X-TTS-Signature')) return res.sendStatus(401);
const { event, generation } = JSON.parse(req.body);
// event = generation.completed | generation.failed
res.sendStatus(200);
});
Errors
400 | Invalid input (empty text, unknown voice, line too long). |
401 | Missing, invalid or revoked key. |
402 | Not enough credits, no plan, or the key's monthly cap is reached. |
403 | Feature not in your plan, or IP / website not allowed for this key. |
413 | Text longer than your plan allows per clip. |
429 | Too many requests per minute. |
502 / 503 | Voice service busy. Nothing is charged — retry shortly. |