TTS API async jobs and webhooks for long scripts — Audra
POST /v2/speech is synchronous: hold the connection, wait minutes, get audio. That works to 50,000 characters, but a long render holding an HTTP connection open for an hour is a timeout waiting to happen — yours, your proxy's, or your serverless platform's. POST /v2/speech/jobs is the long-form answer: queue the text, get a job id, collect the audio later.
This post is the jobs API reference: request shape, status lifecycle, polling versus webhooks, the three queue modes, and the failure modes to handle.
Creating a job
The job body is the same shape as sync speech — model, text, voice, format, delivery_profile — plus job-specific fields: webhook_url and mode. text accepts up to 500,000 characters; anything past that must be split by you, at chapter or section boundaries.
curl
curl https://audratalks.com/v2/speech/jobs \
-H "Authorization: Bearer sk-audra-..." \
-H "Content-Type: application/json" \
-d '{"model":"audra-essential","voice":"june","text":"<your long-form text up to 500k chars>","format":"mp3","mode":"standard","webhook_url":"https://yourapp.example/hooks/tts"}'
Python
import requests
resp = requests.post(
"https://audratalks.com/v2/speech/jobs",
headers={"Authorization": "Bearer sk-audra-..."},
json={
"model": "audra-essential",
"voice": "june",
"text": long_text,
"format": "mp3",
"mode": "standard",
"webhook_url": "https://yourapp.example/hooks/tts",
},
timeout=60,
)
resp.raise_for_status()
job = resp.json() # {"job_id": "job_...", ...}
JavaScript
const res = await fetch("https://audratalks.com/v2/speech/jobs", {
method: "POST",
headers: { Authorization: "Bearer sk-audra-...", "Content-Type": "application/json" },
body: JSON.stringify({
model: "audra-essential",
voice: "june",
text: longText,
format: "mp3",
mode: "standard",
webhook_url: "https://yourapp.example/hooks/tts",
}),
});
if (!res.ok) throw new Error(await res.text());
const job = await res.json(); // { job_id: "job_...", ... }
Status lifecycle
A job moves through queued → processing → completed (or failed). Poll GET /v2/speech/jobs/{id} for the current status; the response includes job_id, status, chars, input_chars, model, mode, voice, format, error (null unless failed), created_at, and completed_at. When status is completed, download the audio from GET /v2/speech/jobs/{id}/audio.
Webhooks versus polling
Pass webhook_url at creation and Audra POSTs { job_id, status, chars } to your endpoint on completion or failure — no polling loop, no sleep-30-seconds scripts. Webhooks win for any pipeline enqueueing more than a couple of jobs. Polling is fine for one-off scripts and for backfilling a webhook your endpoint missed. Verify your handler is idempotent: delivery retries can fire more than once for the same job.
Queue modes: standard, fast, economy
mode is jobs-only. standard (1.0x credits) is the default. fast buys queue priority at 1.25x. economy defers rendering to the next scheduled sweep (roughly every 12 hours, or sooner if a worker is already warm) at 0.75x credits — 25% off for batch work with no deadline. Sending mode economy on the synchronous /v2/speech endpoint returns 400; economy exists only on jobs.
Failure modes and fixes
- Job status failed with error text: log error, fix the cause (usually text content), re-enqueue that job only — other queued jobs are unaffected.
- Auto-queueing surprise: sync POST /v2/speech requests above roughly 8,000 characters are silently converted to background jobs unless you send X-Audra-Sync: true. If your code expects audio bytes back, either chunk under 8k or handle the job-shaped response.
- Webhook endpoint down: jobs still complete; poll /v2/speech/jobs/{id} as a fallback and reconcile.
- Long polls hammering: poll every 30–60 seconds, not every second — completed jobs stay downloadable.
When to stay synchronous
Under ~8,000 characters with a patient client, sync /v2/speech is simpler: one request, audio bytes in the response, X-QA-Passed header to check. Jobs earn their complexity when renders run long, when you batch many files, or when your runtime caps request duration.
The audiobook pipeline built on jobs: the audiobook chapters post. Billing behavior of failed renders: the QA-gated billing post. Full parameter reference: /docs.