Voiceover
audioaudio/voiceoverOver 120 studio voices read your script in the language you write it, at the pace and pauses you set.
Pick a voice from the shared catalog (GET /v3/voices) or use one of your own clones, send a script, get an audio file. Pace is normalised per voice before your speed multiplier applies, so 1 already sounds right and 1.1 means slightly faster than that voice's natural read, not faster than raw model output.
Billed per started 1,000 characters of script. $0.15 per block: a 600 character script and a 1,400 character one cost one block and two. Live rate from GET /v3/pricing.
A complete call
Read a short script in a catalog voice, with one exact pause.
1Pick a voice
GET /v3/voices returns the shared catalog, each with a presigned audition clip. Hardcode the slug, not the uuid: the slug is the stable handle. Your own clones sort first and are the smaller shape: owner "project", no slug, tags, locale or preview.
curl "https://api.neurall.io/v3/voices?tag=female&tag=narration" \
-H "Authorization: nl-YOUR_API_KEY"It answers with the catalog
{
"voices": [
{
"id": "d77c…",
"owner": "project",
"status": "done",
"name": "Founder voice"
},
{
"id": "3f7c1a92-5d84-4b16-9e03-7c2a5f81d6b4",
"owner": "neurall",
"status": "done",
"slug": "aria",
"name": "Aria",
"description": "Warm, unhurried, mid-range. Reads long copy without tiring.",
"tags": [
"female",
"warm",
"narration"
],
"locale": "en-US",
"preview": "https://cdn.neurall.io/…/aria.mp3"
}
]
}2Submit the script
POST /v3/generations with the text and the slug from step 1. No upload step: there is no reference file.
curl -X POST "https://api.neurall.io/v3/generations" \
-H "Authorization: nl-YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"feature": "audio/voiceover",
"args": {
"text": "Introducing the Aurora 3. [pause=0.8] The lightest frame we have ever built.",
"voiceId": "aria",
"speed": 1
}
}'It answers immediately
{
"generation": {
"id": "8f13…",
"feature": "audio/voiceover",
"kind": "audio",
"status": "pending"
}
}3Poll until it lands
Speech is quick, usually seconds. Poll GET /v3/generations/{id}, or pass webhookUrl and skip polling.
# repeat every 2s or so until status is done, error or timeout
curl "https://api.neurall.io/v3/generations/9f2c1d84-6a3b-4f21-9c77-2f0a1b8e5d43" \
-H "Authorization: nl-YOUR_API_KEY"Once status is done
{
"generation": {
"status": "done",
"output": {
"audio": "https://cdn.neurall.io/…/speech.mp3",
"mime": "audio/mpeg"
}
}
}output holds the finished asset on a signed CDN URL. Download it rather than hotlinking: API-created outputs expire 24 hours after the request.
Arguments
textstringrequired- The script. [pause=1.5] inserts an exact 1.5 second pause, and pauses survive the pace pass untouched.
- At most 5000 characters per call.
- A single pause may not exceed 30 seconds.
voiceIdstringrequired- A catalog voice id or its slug (the stable handle worth hardcoding), or the id of one of your cloned voices.
- Both catalog voices and your own clones come from GET /v3/voices; filter with ?owner=.
- The list is a union of two shapes, discriminated by owner: catalog rows (owner "neurall") carry slug, tags, locale and preview; your clones (owner "project") carry only id, status, name and description. Branch on owner, not on which fields exist.
args.voiceIdThe voice- An id or a slug, not a description. Asking for "a warm female voice" in the text will simply be read aloud.
speednumberdefaults to 1- Relative to the voice's normalised pace. Omit it at 1.
- Between 0.5 and 2.
stabilitynumber- How steady the read is. Lower wanders more, higher is flatter and more consistent.
stylenumber- How expressive the read is. Pairs with stability; the app ships two presets rather than exposing both dials.
languagestring- Hints the language when the script is ambiguous. Omit it, or send "auto", and it is detected from the script. The older languageBoost spelling still works.
How the prompt refers to this
Anything you put in text is spoken, including stage directions. Use the arguments for delivery, not prose.
Output
Once status is done, the generation carries an output object with these fields. On any other status, output is absent.
audiostring- The finished read, as a URL.
- A signed URL that expires 24 hours after the request (expiresAt on the generation). Download the file rather than hotlinking it.
mimestring- The file's MIME type, e.g. audio/mpeg.
Limits and failure
- Script
- At most 5000 characters per call, billed per started 1,000.
- Pauses
- [pause=N] up to 30 seconds each.
- Speed
- Between 0.5 and 2, relative to the voice's normalised pace.
- Concurrency
- Your plan caps how many generations run at once. Over it the API answers 429 with a Retry-After header.
- Output lifetime
- API-created outputs expire 24 hours after the request. Download the file rather than hotlinking it.
- Deletion
- DELETE /v3/generations/{id} removes the generation and its rendered assets immediately, rather than waiting for the 24 hour expiry. It does not refund anything and cannot cancel a render already in flight.
- Failure
- A failed or timed-out generation is refunded automatically.
Worth knowing
- The catalog is identical for every caller, so a voice id you hardcode today keeps meaning the same voice.
- Pace and pauses are applied after synthesis with ffmpeg rather than asked of the model, which is why an exact pause is exact.