How to Convert Text to Speech with a REST API
Building an app that reads text aloud? Whether you're narrating articles, generating podcast scripts, or making your product more accessible, a TTS API is the simplest path. This guide walks through the NarrateAI API from first request to downloaded audio file.
Prerequisites
You'll need:
- An API key (get one free here — no credit card required)
curlor Python 3.8+
That's it. No SDKs to install, no client libraries. It's plain HTTP.
Step 1: Submit a narration job
NarrateAI processes text asynchronously. You submit a job and get back a job ID immediately — the audio is ready moments later depending on length.
curl -X POST https://api.narrateai.mossforge.dev/v1/tts/async \
-H "Authorization: Bearer nai_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"text": "The quick brown fox jumped over the lazy dog.",
"lang": "en",
"voice": "michael"
}'
The response comes back immediately:
{
"job_id": "888d45c5-1234-5678-abcd-ef0123456789",
"status": "processing",
"total_chunks": 1,
"total_chars": 45,
"estimated_seconds": 3,
"poll_url": "/v1/tts/async/888d45c5-..."
}
Save the job_id — you'll need it to fetch the result.
Step 2: Poll for completion
Short texts finish in a few seconds. Poll the job endpoint until status is complete:
curl https://api.narrateai.mossforge.dev/v1/tts/async/888d45c5-1234-5678-abcd-ef0123456789 \
-H "Authorization: Bearer nai_your_key_here"
When it's ready:
{
"job_id": "888d45c5-...",
"status": "complete",
"progress_percent": 100.0,
"url": "https://s3.amazonaws.com/...",
"duration_seconds": 3.2
}
The url is a presigned S3 link valid for 1 hour. Download it before it expires — the file itself is stored for 7 days.
Step 3: Download the audio
curl -o narration.wav "https://s3.amazonaws.com/..."
You now have a WAV file. Done.
Python example
Here's a complete script that submits a job and waits for it:
import time
import httpx
API_KEY = "nai_your_key_here"
BASE_URL = "https://api.narrateai.mossforge.dev"
HEADERS = {"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"}
def narrate(text: str, lang: str = "en", voice: str = "michael") -> str:
# Submit job
resp = httpx.post(f"{BASE_URL}/v1/tts/async", headers=HEADERS, json={
"text": text, "lang": lang, "voice": voice,
})
resp.raise_for_status()
job_id = resp.json()["job_id"]
print(f"Job submitted: {job_id}")
# Poll until complete
while True:
status = httpx.get(f"{BASE_URL}/v1/tts/async/{job_id}", headers=HEADERS).json()
print(f" {status['progress_percent']:.0f}% complete")
if status["status"] == "complete":
return status["url"]
if status["status"] == "failed":
raise RuntimeError(f"Job failed: {status.get('error')}")
time.sleep(2)
audio_url = narrate("Hello from NarrateAI. This is a test narration.")
print(f"Audio ready: {audio_url}")
Choosing a voice
NarrateAI ships with 10 voice styles — 5 male, 5 female. Pass the name or the ID:
| Name | Character |
|---|---|
michael |
Male, natural (default) |
emily |
Female, natural |
richard |
Male, British accent |
cassandra |
Female, British accent |
alex |
Male, expressive |
Working with long documents
The 100,000 character limit per job covers roughly a 75-page document or a full hour of audio. For a 10,000-word article, the API handles chunking and stitching internally — you still get back a single WAV file.
curl -X POST https://api.narrateai.mossforge.dev/v1/tts/async \
-H "Authorization: Bearer nai_your_key_here" \
-H "Content-Type: application/json" \
-d "{\"text\": \"$(cat my-article.txt)\", \"lang\": \"en\", \"voice\": \"emily\"}"
Expression tags
Want the voice to sound more human? Inline expression tags adjust delivery:
She paused. <breath> "I wasn't expecting that," she said with a <laugh> laugh.
Supported tags: <laugh>, <sigh>, <breath>, <scream>, <surprise>, <yawn>, <cough>, <throatclear>, <angry>, <sad>
What's next
- Check your usage via
GET /v1/accounts/me/usage - Upgrade your plan if you're hitting your monthly quota
- Try a different language — all 31 are supported at the same price
Get started
Try NarrateAI free
125,000 characters on signup. No credit card required.
Get your API key →