Text-to-speech API with token authentication, supporting 81 languages and regions and 692 voices
Terms of provision
token header (how to get it)The Standard TTS API requires an access token (64 characters). After you create an account, you can get it from the settings page.
Keep it secret: Do not share your access token with anyone. A third party who has it can use the service as you. If it leaks, you can reissue it on the settings page.
The samples on this page assume the token is stored in the environment variable ONDOKU_TOKEN.
| Header | Value |
|---|---|
Content-Type | application/json |
token | Access token (64 characters) |
All 4 fields are required. If any of them is missing, the API returns HTTP 400.
| Field | Type | Required | Description |
|---|---|---|---|
voice | string | Required | Voice ID (e.g. en-US-JennyNeural). See the voice list |
text | string | Required | Text to read aloud (must not be empty) |
speed | number | Required | Speed (valid range: 0.3 to 4.0, e.g. 1.0). Out-of-range values are treated as the default 1.0 |
pitch | number | Required | Pitch (valid range: -20 to 20, e.g. 0.0). Out-of-range values are treated as the default 0 |
On success, the API returns application/json with the URL of the generated audio and the history ID. Fetch the MP3 binary from url.
{
"text": "Hello, this is Ondoku.",
"url": "https://storage.googleapis.com/ondoku3/voice/...",
"pk": 12345,
"share": 1
}
| Field | Type | Description |
|---|---|---|
text | string | The text that was read aloud |
url | string | URL of the generated audio file, without the query string |
pk | number | ID of the generation history entry (Sentence) |
share | number | Share flag. Usually 1; 0 for some error audio |
On failure, the API usually returns JSON {"error": "..."}. Only rate-limit responses also include reset_in.
Notice responses that are not HTTP errors: In some cases, such as when your monthly character allowance is insufficient, the API returns HTTP 200 with JSON in the same shape as above, and url points to a notice audio file. Do not judge success by the HTTP status alone; also check the returned text / url.
curl -X POST https://ondoku3.com/text_to_speech_api/ \
-H "Content-Type: application/json" \
-H "token: $ONDOKU_TOKEN" \
-d '{
"voice": "en-US-JennyNeural",
"text": "Hello, this is Ondoku.",
"speed": 1.0,
"pitch": 0.0
}' \
| tee response.json
curl -L "$(jq -r .url response.json)" -o output.mp3
import os
import requests
resp = requests.post(
"https://ondoku3.com/text_to_speech_api/",
headers={
"Content-Type": "application/json",
"token": os.environ["ONDOKU_TOKEN"],
},
json={
"voice": "en-US-JennyNeural",
"text": "Hello, this is Ondoku.",
"speed": 1.0,
"pitch": 0.0,
},
timeout=60,
)
resp.raise_for_status()
data = resp.json()
mp3 = requests.get(data["url"], timeout=60).content
with open("output.mp3", "wb") as f:
f.write(mp3)
print(f"saved: output.mp3 ({len(mp3)} bytes), pk={data['pk']}")
import { writeFile } from "node:fs/promises";
const token = process.env.ONDOKU_TOKEN!;
const res = await fetch("https://ondoku3.com/text_to_speech_api/", {
method: "POST",
headers: {
"Content-Type": "application/json",
token,
},
body: JSON.stringify({
voice: "en-US-JennyNeural",
text: "Hello, this is Ondoku.",
speed: 1.0,
pitch: 0.0,
}),
});
if (!res.ok) throw new Error(`HTTP ${res.status}: ${await res.text()}`);
type StandardTTSResponse = {
text: string;
url: string;
pk: number;
share: number;
};
const data = (await res.json()) as StandardTTSResponse;
const audioRes = await fetch(data.url);
if (!audioRes.ok) throw new Error(`audio HTTP ${audioRes.status}: ${await audioRes.text()}`);
const buf = Buffer.from(await audioRes.arrayBuffer());
await writeFile("output.mp3", buf);
console.log(`saved: output.mp3 (${buf.byteLength} bytes), pk=${data.pk}`);
| HTTP | Example | Cause |
|---|---|---|
| 200 | {"text": "...", "url": "...", "pk": ..., "share": ...} | Notice audio JSON, for example when characters are insufficient. Check the audio at url |
| 400 | Token does not exists | The token header is missing or is not 64 characters |
| 400 | Token does not match | Invalid token |
| 400 | voice parameter is required | voice is missing or is not a string |
| 400 | Unsupported voice requested. | The voice is not in the voice list |
| 400 | Please set "voice", "speed", "pitch", "text" | One of the 4 required fields is missing |
| 400 | "speed" and "pitch" must be finite numbers | speed / pitch is NaN or Infinity |
| 429 | Rate limit exceeded | More than 30 requests in 60 seconds (per client IP address) |
| 500 | Internal server error | Server-side error (retry after a while) |
For plan details and prices, see the pricing page.
| HTTP | What to do |
|---|---|
| 429 (Rate limit) | Wait reset_in seconds from the response, or at least 2 seconds, then retry |
| 5xx | Exponential backoff (1 second → 2 seconds → 4 seconds → 8 seconds, up to 3 times) |
| 4xx (such as 400; authentication errors are also 400) | Do not retry. Fix the request |
| Network timeout | Retry up to 2 to 3 times. The same text and voice return the same audio |
The following uses are prohibited:
See the Terms of Service for details.
Ondoku's official APIs provide the following monthly uptime as their SLA. The definitions in this section (how uptime is measured, what is excluded, and what happens if the SLA is missed) apply to both APIs.
| API | Endpoint | SLA (monthly uptime) |
|---|---|---|
| Standard TTS API | POST /text_to_speech_api/ | 99.0% |
| Advanced TTS API (Beta) | POST /api/advanced-tts/GET /api/advanced-tts/jobs/{job_id}/ | 98.0% |
The SLA covers uptime only, not response time.
status is failed) does not count as downtimeBreaking changes (removing fields, changing types or meaning, retiring endpoints, and so on) are announced in this section 30 days before they take effect. Notable backward-compatible changes such as new fields or voices are also recorded in this section after release (no advance notice). Urgent security fixes are an exception.
| Date | Change |
|---|---|
| 2026-10-02 | Started the rule of announcing breaking changes in this section 30 days in advance. Added the Advanced TTS API (Beta, 98.0% monthly uptime) to the SLA section |
| 2026-10-01 | Set an SLA (99.0% monthly uptime) as an official API |
If you run into a bug or unexpected behavior, try the following first:
{"voice":"en-US-JennyNeural","text":"Test","speed":1.0,"pitch":0.0} returns 200If that does not solve it, contact us through the contact form. Including the following information helps us reproduce the issue:
About specification changes: API specification changes are recorded in the Changelog. Breaking changes are announced 30 days before they take effect.