API Reference
Complete reference for the SayIt API • Base URL: https://api.sayitapi.com • Version: v1
Overview
The SayIt API converts text to speech and returns a signed audio URL. There are no streaming endpoints, no WebSocket connections, and no SDKs required - just a single JSON endpoint.
Requests are authenticated using an SAYIT-API-KEY header. Get your API key from your dashboard.
Authentication
All requests must include your API key in the SAYIT-API-KEY header. API keys are prefixed with sk_live_ for production and sk_test_ for sandbox testing.
SAYIT-API-KEY: sk_live_your_api_key_hereEndpoint
https://api.sayitapi.com/v1/ttsThis is the only endpoint in v1. Submit text and configuration parameters, receive a JSON response with your audio URL.
Parameters
Send a JSON body with the following fields:
| Parameter | Type | Required | Description |
|---|---|---|---|
| text | string | Yes | Text to synthesize. Max length depends on your plan (1,000–10,000 chars). |
| voice_id | string | No | Voice: eve, ara, rex, sal, or leo. Default: eve. |
| language | string | No | BCP-47 language code (e.g. "en", "es", "fr") or "auto" for auto-detect. Default: auto. |
| output_format | string | No | "mp3" or "wav". Default: mp3. |
| speech_tags | boolean | No | Enable SSML-like speech tag parsing. Default: false. |
| speed | number | No | Speaking speed multiplier. Range: 0.5–2.0. Default: 1.0. |
| sample_rate | integer | No | Audio sample rate in Hz: 8000, 16000, 22050, or 44100. Default: 22050. |
Response fields
| Field | Type | Description |
|---|---|---|
| id | string | Unique request ID (tts_01h...). |
| status | string | "completed" on success. |
| audio_url | string | URL to the generated audio file, valid for 24 hours. Serve directly or download. |
| duration_seconds | number | Length of the generated audio in seconds. |
| characters_used | integer | Billable characters consumed by this request. |
| voice_id | string | Voice used for this request. |
| created_at | string | ISO 8601 timestamp of when the request was processed. |
Code Examples
cURL
curl -X POST https://api.sayitapi.com/v1/tts \
-H "SAYIT-API-KEY: sk_live_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"text": "Hello! This is <emphasis>SayIt API</emphasis>.",
"voice_id": "eve",
"language": "en",
"output_format": "mp3",
"speech_tags": true
}'Python
import requests
response = requests.post(
"https://api.sayitapi.com/v1/tts",
headers={
"SAYIT-API-KEY": "sk_live_your_api_key_here",
"Content-Type": "application/json",
},
json={
"text": "Hello! This is SayIt API.",
"voice_id": "eve",
"language": "en",
"output_format": "mp3",
"speech_tags": False,
},
timeout=15,
)
response.raise_for_status()
data = response.json()
print(data["audio_url"]) # Stream or download this URL
print(data["duration_seconds"]) # e.g. 2.8
print(data["characters_used"]) # billed charactersJavaScript / TypeScript
interface TtsResponse {
id: string;
status: string;
audio_url: string;
duration_seconds: number;
characters_used: number;
voice_id: string;
created_at: string;
}
async function synthesize(text: string): Promise<TtsResponse> {
const res = await fetch("https://api.sayitapi.com/v1/tts", {
method: "POST",
headers: {
"SAYIT-API-KEY": process.env.SAYIT_API_KEY!,
"Content-Type": "application/json",
},
body: JSON.stringify({
text,
voice_id: "eve",
language: "en",
output_format: "mp3",
}),
});
if (!res.ok) {
const error = await res.json();
throw new Error(`SayIt error: ${error.error.code} - ${error.error.message}`);
}
return res.json();
}Rate Limits
Rate limits apply per API key. When exceeded, requests return a 429 status with a Retry-After header.
| Plan | Req / min | Concurrent | Max text (chars) |
|---|---|---|---|
| Free | 10 | 1 | 1,000 |
| Paid | 200 | 10 | 10,000 |
Error Codes
Errors return a JSON body with an error object containing code, message, and optionally param.
{
"error": {
"code": "rate_limit_exceeded",
"message": "You have exceeded 200 requests per minute. Retry after 18 seconds.",
"retry_after": 18
}
}| Code | HTTP | Description |
|---|---|---|
| invalid_api_key | 401 | API key is missing, malformed, or revoked. |
| rate_limit_exceeded | 429 | Requests per minute limit exceeded. Check Retry-After header. |
| text_too_long | 400 | Text exceeds the maximum character limit for your plan. |
| invalid_voice | 400 | voice_id is not recognized. Use: eve, ara, rex, sal, or leo. |
| invalid_language | 400 | language code is not valid BCP-47 or unsupported. |
| quota_exceeded | 402 | Monthly character quota exhausted. Upgrade or wait for reset. |
| invalid_request | 400 | Malformed JSON, missing required fields, or invalid parameter value. |
| server_error | 500 | Internal server error. Our team is automatically alerted. |
Questions? support@sayitapi.com