Course narration TTS API: lesson modules at batch economics — Audra
An online course is a folder of scripts that changes a few times a year and gets re-rendered when it does. That is the opposite of a realtime workload. Course narration is a batch file factory: script in, mastered MP3 out, one voice per course, stored next to your video assets.
This post is the full pipeline for course authors and LMS platform teams: how to size lessons, which voice to lock, and what a finished course hour actually costs at Audra's prepaid $25/1M characters on Essential.
The persona: a 20-lesson technical course
Work with the shape you actually have. A 20-lesson course at roughly 12 minutes of narration each is about 9,000 characters per lesson, so the whole course is around 180,000 characters. Each lesson fits comfortably inside the 50k sync limit — one POST per lesson, no chunking code needed.
Rendering loop, one lesson at a time
Send each lesson script to POST /v2/speech with format mp3. Output is 128 kbps at −16 LUFS, which sits at the loudness level course players and headphones expect, so no post-processing pass is required before upload.
curl
curl https://audratalks.com/v2/speech \
-H "Authorization: Bearer sk-audra-..." \
-H "Content-Type: application/json" \
-d '{"model":"audra-essential","voice":"arthur","text":"Module 3: Joins...","format":"mp3"}' \
--output module-03.mp3
Python
import requests
resp = requests.post(
"https://audratalks.com/v2/speech",
headers={"Authorization": "Bearer sk-audra-..."},
json={"model": "audra-essential", "voice": "arthur", "text": lesson_text, "format": "mp3"},
timeout=3600,
)
resp.raise_for_status()
if resp.headers.get("X-QA-Passed") != "true":
raise RuntimeError("lesson failed QA - will not be billed")
open("module-03.mp3", "wb").write(resp.content)
JavaScript
const res = await fetch("https://audratalks.com/v2/speech", {
method: "POST",
headers: { Authorization: "Bearer sk-audra-...", "Content-Type": "application/json" },
body: JSON.stringify({ model: "audra-essential", voice: "arthur", text: lessonText, format: "mp3" }),
});
if (!res.ok) throw new Error(await res.text());
if (res.headers.get("X-QA-Passed") !== "true") throw new Error("lesson failed QA");
await writeFile("module-03.mp3", Buffer.from(await res.arrayBuffer()));
Two details matter here. First, timeouts: batch narration is not sub-second; plan HTTP timeouts of at least 3600 seconds. Second, X-QA-Passed: the response header tells you the render passed automated QA. Failed gates auto-refund, so a broken lesson never silently burns budget.
Chunking strategy for courses
Don't chunk. Lessons under 50,000 characters go in a single sync request. Only if a single script runs longer — rare in courseware — split at section boundaries, not mid-sentence, so joins land in paragraph pauses. For genuinely oversized material (compiled full-course narration, multi-course bundles), POST /v2/speech/jobs accepts up to 500k characters per job.
Voice: pick one slug and never change it
Learners recognize a course by its narrator. Pick one Essential voice — arthur reads technical material at a measured pace; june is warmer for soft-skills content — and hard-code it in your render config. Audra has no cloning, so the slug is deterministic: re-recorded lessons next quarter get the same voice, with zero drift.
Cost per course hour, at real course numbers
One hour of finished course audio is roughly 55,000 characters of script. At $25/1M prepaid on Essential (1.0x multiplier), that is $1.38 per course hour, and a full 20-lesson / 180k-character course costs about $4.50 to narrate — roughly the price of one freelance voice take, once, for the entire catalog. Model your own lesson mix on /calc before budget season.
Watch-outs specific to courseware
- Code samples and CLI flags read badly aloud — rewrite them for the ear or wrap them in <say-as interpret-as="characters"> before rendering.
- normalize (default true) expands URLs and emails into speakable words; if a lesson literally teaches URL syntax, set normalize false.
- Screen-recording sync: render audio first, then time the video to it — doing it the other way around produces drift.
- Trial credits are 25k characters and evaluation-only; buy a $5 pack (200k chars) before shipping to students, which also unlocks commercial use (send X-Audra-Commercial-Use: true on production renders).
Per-episode podcast economics live in the podcast post; per-course-hour math stays here. Voice catalog for picking your narrator: /voices. Calculator: /calc.