Captioned speech API: words + timings with your MP3 — Audra

POST /v2/speech/captioned is a separate endpoint that returns what /v2/speech returns — MP3 or WAV — plus word-level timestamps, delivered in the X-Captions-Json response header. One request, audio and subtitles together, which is exactly what video editors, highlight tools, and read-along UIs need.

This post is the endpoint reference: the header format, the accuracy contract, the 50k limit, and what to build on top of it.

The request

Same body as speech — model, text, voice, format, speed — sent to /v2/speech/captioned. Same 50,000-character cap. The audio comes back as the response body; the timestamps ride along in X-Captions-Json.

curl
curl https://audratalks.com/v2/speech/captioned \
  -H "Authorization: Bearer sk-audra-..." \
  -H "Content-Type: application/json" \
  -d '{"model":"audra-essential","voice":"june","text":"Chapter one: the arrival...","format":"mp3"}' \
  -D headers.txt \
  --output chapter-01.mp3
Python
import json, requests

resp = requests.post(
    "https://audratalks.com/v2/speech/captioned",
    headers={"Authorization": "Bearer sk-audra-..."},
    json={"model": "audra-essential", "voice": "june", "text": text, "format": "mp3"},
    timeout=3600,
)
resp.raise_for_status()
open("chapter-01.mp3", "wb").write(resp.content)
words = json.loads(resp.headers["X-Captions-Json"])["words"]
# [{"word": "Chapter", "start": 0.0, "end": 0.6}, ...]
JavaScript
const res = await fetch("https://audratalks.com/v2/speech/captioned", {
  method: "POST",
  headers: { Authorization: "Bearer sk-audra-...", "Content-Type": "application/json" },
  body: JSON.stringify({ model: "audra-essential", voice: "june", text, format: "mp3" }),
});
if (!res.ok) throw new Error(await res.text());
await writeFile("chapter-01.mp3", Buffer.from(await res.arrayBuffer()));
const { words } = JSON.parse(res.headers.get("X-Captions-Json"));
// [{ word: "Chapter", start: 0.0, end: 0.6 }, ...]

The timestamps and their contract

Each entry is a word with start and end in seconds. The honest caveat: these are duration-weighted estimates, not forced alignment — accurate enough for subtitles, karaoke highlighting, and chapter scrubbing, not frame-accurate lip-sync. If you need broadcast-grade sync, plan a light alignment pass on top.

What people build with it

Failure modes

Audio-only rendering: the docs quickstart. The listen-mode player pattern: the accessibility post. Full API reference: /docs.