Speech to text — inline for short audio, stream=true for newline-delimited segments, queued for long.
When and why to call these: the transcription guide.
Transcribe audio, queued
Section titled “Transcribe audio, queued”POST /v1/transcriptions
Accepts the request, charges an estimate and returns immediately with a gen_… id. Poll GET /v1/transcriptions/{id} until status is succeeded or failed.
Name a recording in your asset library with asset_id — upload it first with POST /v1/assets/upload-url. The audio is kept: transcribing it twice costs one upload.
Use /v1/stt instead if the audio is short. This route is for what a queue makes possible: files up to the platform’s limits.uploads.audio_bytes (GET /v1/platform/limits), audio of any length, and a result that lands in your library as JSON with the word timestamps in it.
The charge is an estimate, then a correction. An asset that has finished processing carries its measured length, so that is what you are quoted; either way it is reconciled against the provider’s own measurement, and transcript.duration_seconds on the finished generation is the figure that was charged. A generation that fails is refunded in full.
curl -X POST "https://api.lumavox.ai/v1/transcriptions" \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -d '{"asset_id":"ast_a1B2c3D4e5F6g7H8"}'Request body (application/json)
| Field | Type | Required | Description |
|---|---|---|---|
asset_id | string | Required | ast_…, from your asset library. Must be audio. 3–32 characters. |
model | "scribe_v2" | One of: scribe_v2. Default "scribe_v2". | |
language | string or null | ISO-639-1 or -639-3 code. Omit it and the language is detected automatically. Set it when you already know – detection is very good and not free of mistakes, and a wrong guess costs the whole transcript. language_code on the response is not this value. It is ISO-639-3 whichever you sent, so en here comes back as eng. | |
diarize | boolean | Label who is speaking. Each word gains a speaker_id. Adds processing time and is not free of error on overlapping speech. Default false. | |
num_speakers | integer or null | The most speakers to look for, when diarize is on. Ignored otherwise. Setting it when you know the number improves the labelling; leaving it out lets the provider decide. 1–32. | |
tag_audio_events | boolean | Mark laughter, applause and similar in the transcript, as (laughter)-style entries with type: audio_event. Default false. | |
timestamps | boolean | Return each word with its start_seconds and end_seconds. Off by default because the array is far larger than the text – an hour of speech is roughly ten thousand entries – and most callers want the text. Default false. | |
folder_id | string or null | fld_… — the folder in your asset library the finished file is filed under. Omit it for the root. A folder that is not yours is a 400, never a silent fall back to the root. |
Responses
| Status | Description |
|---|---|
202 |
application/json — Accepted and charged. Poll GET /v1/transcriptions/{id} |
400 |
That asset is not audio, failed to process, or has no stored audio; or a folder that is not one |
401 |
Missing or invalid credentials |
402 |
Out of credits, or the organisation is suspended — nothing was charged |
403 |
The key is valid but its scopes do not cover this capability — a key limited to tts gets this from /v1/images rather than a 401 |
404 |
No such asset |
409 |
That asset is still being processed |
422 |
The request failed validation |
429 |
Rate limit exceeded |
503 |
Object storage or the provider is not configured here |
202 response body
| Field | Type | Description |
|---|---|---|
id |
string | gen_…. Poll this. |
status |
"queued", "submitted", "running", "succeeded", "failed", "moderated" |
queued, submitted and running mean keep polling. succeeded, failed and moderated are terminal — stop. |
capability |
"tts", "image", "video", "stt", "skybox" |
|
model |
string or null | |
prompt |
string or null | |
aspect_ratio |
string or null | |
width |
integer or null | |
height |
integer or null | |
output_format |
string or null | |
seed |
integer or null | |
megapixels |
number or null | |
safety_tolerance |
integer or null | |
enhance_prompt |
boolean or null | |
folder_id |
string or null | fld_… the result lands in, or null for the root. |
duration |
integer or null | Seconds asked for. Video only. |
resolution |
string or null | hd or fhd. Video only. |
generate_audio |
boolean or null | |
start_frame |
string or null | |
end_frame |
string or null | |
negative_text |
string or null | |
style_id |
integer or null | |
init_image |
string or null | |
init_strength |
number or null | |
voice_id |
string or null | |
speech |
TTSOptions or null | The voice and model a speech generation ran with. |
speech.voice_id |
string | An id from GET /v1/voices — the built-in voice, a platform voice, or one your organisation uploaded. |
speech.model |
string | Which model speaks: one of the voice’s models in GET /v1/voices — eleven_flash_v2_5 (the fastest, and the default), eleven_multilingual_v2 or eleven_v3. A model the voice does not list is refused. |
speech.provider_options |
ProviderVoiceSettingsInfo or null | The provider’s voice settings sent on top of the voice’s own; null took theirs. |
speech.provider_options.stability |
number or null | Low is more expressive and less consistent between generations; high is flatter and more repeatable. |
speech.provider_options.similarity_boost |
number or null | How closely to cling to the original voice. High can reproduce artefacts in the source. |
speech.provider_options.style |
number or null | Style exaggeration. Costs latency; leave unset on anything conversational. |
speech.provider_options.use_speaker_boost |
boolean or null | Similarity at the cost of latency. |
speech.provider_options.speed |
number or null | 1.0 is the voice’s own pace. |
speech.format |
"wav", "pcm" |
|
speech.sample_rate |
8000, 16000, 22050, 24000, 44100 or null |
Hz of the returned audio — one of 8000, 16000, 22050, 24000, 44100, each served natively by the provider. Unset means 24000. POST /v1/tts says what it produced in the X-Sample-Rate header. Queued speech (POST /v1/audio) does not take it: each of its formats has its own rate. |
credits_micros |
integer or null | What was debited when this was accepted, in micro-credits (1 credit is 1,000,000). A failure refunds it in full; a transcription’s is corrected to the measured length when it finishes. |
template_id |
string or null | |
image |
GenerationImage or null | |
image.asset_id |
string or null | The library entry this generation produced. |
image.url |
string or null | A short-lived link to the file. Minted per response and not stored — fetch the asset again for a fresh one. |
image.width |
integer or null | |
image.height |
integer or null | |
image.content_type |
string or null | |
image.size_bytes |
integer or null | |
video |
GenerationVideo or null | |
video.asset_id |
string or null | The library entry this generation produced. |
video.url |
string or null | A short-lived link to the file. Minted per response and not stored — fetch the asset again for a fresh one. |
video.width |
integer or null | |
video.height |
integer or null | |
video.duration_seconds |
number or null | |
video.content_type |
string or null | |
video.size_bytes |
integer or null | |
video.has_thumbnail |
boolean or null | |
audio |
GenerationAudio or null | |
audio.asset_id |
string or null | The library entry this generation produced. |
audio.url |
string or null | A short-lived link to the file. Minted per response and not stored — fetch the asset again for a fresh one. |
audio.duration_seconds |
number or null | |
audio.content_type |
string or null | |
audio.size_bytes |
integer or null | |
audio.peaks |
array of integer or null | Waveform magnitudes, 0-100, for a mirrored strip; null when never computed. |
transcript |
GenerationTranscript or null | |
transcript.text |
string or null | The transcript, as one string. |
transcript.language_code |
string or null | |
transcript.language_probability |
number or null | |
transcript.duration_seconds |
number or null | |
transcript.word_count |
integer or null | |
transcript.asset_id |
string or null | The library entry holding the full JSON. |
transcript.content_type |
string or null | |
transcript.size_bytes |
integer or null | |
transcript.url |
string or null | |
skybox |
GenerationSkybox or null | |
skybox.asset_id |
string or null | The library entry this generation produced. |
skybox.url |
string or null | A short-lived link to the file. Minted per response and not stored — fetch the asset again for a fresh one. |
skybox.preview_url |
string or null | A short-lived link to the 2K WebP, which is what to load in a 360 viewer. |
skybox.width |
integer or null | |
skybox.height |
integer or null | |
skybox.content_type |
string or null | |
skybox.size_bytes |
integer or null | |
skybox.has_thumbnail |
boolean or null | |
skybox.files |
array of SkyboxFile | Every file the environment was stored as, in plan order. |
skybox.files[].name |
string | hdr-4k, hdr-2k, png-8k, png-4k, png-2k, preview-2k, depth-2k. |
skybox.files[].content_type |
string | |
skybox.files[].url |
string or null | Short-lived link. Minted per response and not stored. |
skybox.files[].width |
integer or null | |
skybox.files[].height |
integer or null | |
skybox.files[].size_bytes |
integer or null | |
error |
string or null | |
created_at |
string (date-time) | |
finished_at |
string (date-time) or null |
Check a transcription
Section titled “Check a transcription”GET /v1/transcriptions/{generation_id}
Poll every couple of seconds until status is terminal. On success transcript.text carries the text inline; transcript.url is a short-lived link to the full provider response as JSON, including word timestamps and speaker labels where they were requested. That JSON is also in your asset library under transcript.asset_id, which is where to fetch it from later.
curl "https://api.lumavox.ai/v1/transcriptions/$GENERATION_ID" \ -H "Authorization: Bearer $API_KEY"Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
generation_id | string | Required |
Responses
| Status | Description |
|---|---|
200 |
application/json — The generation — the transcript once succeeded |
400 |
The request could not be read: malformed JSON |
401 |
Missing or invalid credentials |
403 |
The key is valid but its scopes do not cover this capability — a key limited to tts gets this from /v1/images rather than a 401 |
404 |
No such generation |
422 |
The request failed validation |
429 |
Rate limit exceeded |
200 response body
| Field | Type | Description |
|---|---|---|
id |
string | gen_…. Poll this. |
status |
"queued", "submitted", "running", "succeeded", "failed", "moderated" |
queued, submitted and running mean keep polling. succeeded, failed and moderated are terminal — stop. |
capability |
"tts", "image", "video", "stt", "skybox" |
|
model |
string or null | |
prompt |
string or null | |
aspect_ratio |
string or null | |
width |
integer or null | |
height |
integer or null | |
output_format |
string or null | |
seed |
integer or null | |
megapixels |
number or null | |
safety_tolerance |
integer or null | |
enhance_prompt |
boolean or null | |
folder_id |
string or null | fld_… the result lands in, or null for the root. |
duration |
integer or null | Seconds asked for. Video only. |
resolution |
string or null | hd or fhd. Video only. |
generate_audio |
boolean or null | |
start_frame |
string or null | |
end_frame |
string or null | |
negative_text |
string or null | |
style_id |
integer or null | |
init_image |
string or null | |
init_strength |
number or null | |
voice_id |
string or null | |
speech |
TTSOptions or null | The voice and model a speech generation ran with. |
speech.voice_id |
string | An id from GET /v1/voices — the built-in voice, a platform voice, or one your organisation uploaded. |
speech.model |
string | Which model speaks: one of the voice’s models in GET /v1/voices — eleven_flash_v2_5 (the fastest, and the default), eleven_multilingual_v2 or eleven_v3. A model the voice does not list is refused. |
speech.provider_options |
ProviderVoiceSettingsInfo or null | The provider’s voice settings sent on top of the voice’s own; null took theirs. |
speech.provider_options.stability |
number or null | Low is more expressive and less consistent between generations; high is flatter and more repeatable. |
speech.provider_options.similarity_boost |
number or null | How closely to cling to the original voice. High can reproduce artefacts in the source. |
speech.provider_options.style |
number or null | Style exaggeration. Costs latency; leave unset on anything conversational. |
speech.provider_options.use_speaker_boost |
boolean or null | Similarity at the cost of latency. |
speech.provider_options.speed |
number or null | 1.0 is the voice’s own pace. |
speech.format |
"wav", "pcm" |
|
speech.sample_rate |
8000, 16000, 22050, 24000, 44100 or null |
Hz of the returned audio — one of 8000, 16000, 22050, 24000, 44100, each served natively by the provider. Unset means 24000. POST /v1/tts says what it produced in the X-Sample-Rate header. Queued speech (POST /v1/audio) does not take it: each of its formats has its own rate. |
credits_micros |
integer or null | What was debited when this was accepted, in micro-credits (1 credit is 1,000,000). A failure refunds it in full; a transcription’s is corrected to the measured length when it finishes. |
template_id |
string or null | |
image |
GenerationImage or null | |
image.asset_id |
string or null | The library entry this generation produced. |
image.url |
string or null | A short-lived link to the file. Minted per response and not stored — fetch the asset again for a fresh one. |
image.width |
integer or null | |
image.height |
integer or null | |
image.content_type |
string or null | |
image.size_bytes |
integer or null | |
video |
GenerationVideo or null | |
video.asset_id |
string or null | The library entry this generation produced. |
video.url |
string or null | A short-lived link to the file. Minted per response and not stored — fetch the asset again for a fresh one. |
video.width |
integer or null | |
video.height |
integer or null | |
video.duration_seconds |
number or null | |
video.content_type |
string or null | |
video.size_bytes |
integer or null | |
video.has_thumbnail |
boolean or null | |
audio |
GenerationAudio or null | |
audio.asset_id |
string or null | The library entry this generation produced. |
audio.url |
string or null | A short-lived link to the file. Minted per response and not stored — fetch the asset again for a fresh one. |
audio.duration_seconds |
number or null | |
audio.content_type |
string or null | |
audio.size_bytes |
integer or null | |
audio.peaks |
array of integer or null | Waveform magnitudes, 0-100, for a mirrored strip; null when never computed. |
transcript |
GenerationTranscript or null | |
transcript.text |
string or null | The transcript, as one string. |
transcript.language_code |
string or null | |
transcript.language_probability |
number or null | |
transcript.duration_seconds |
number or null | |
transcript.word_count |
integer or null | |
transcript.asset_id |
string or null | The library entry holding the full JSON. |
transcript.content_type |
string or null | |
transcript.size_bytes |
integer or null | |
transcript.url |
string or null | |
skybox |
GenerationSkybox or null | |
skybox.asset_id |
string or null | The library entry this generation produced. |
skybox.url |
string or null | A short-lived link to the file. Minted per response and not stored — fetch the asset again for a fresh one. |
skybox.preview_url |
string or null | A short-lived link to the 2K WebP, which is what to load in a 360 viewer. |
skybox.width |
integer or null | |
skybox.height |
integer or null | |
skybox.content_type |
string or null | |
skybox.size_bytes |
integer or null | |
skybox.has_thumbnail |
boolean or null | |
skybox.files |
array of SkyboxFile | Every file the environment was stored as, in plan order. |
skybox.files[].name |
string | hdr-4k, hdr-2k, png-8k, png-4k, png-2k, preview-2k, depth-2k. |
skybox.files[].content_type |
string | |
skybox.files[].url |
string or null | Short-lived link. Minted per response and not stored. |
skybox.files[].width |
integer or null | |
skybox.files[].height |
integer or null | |
skybox.files[].size_bytes |
integer or null | |
error |
string or null | |
created_at |
string (date-time) | |
finished_at |
string (date-time) or null |
Transcribe audio
Section titled “Transcribe audio”POST /v1/stt
Send audio and get the text back — as multipart/form-data with a file part, or as the raw body with the options as query parameters. Any format the provider reads is accepted. stream=true returns newline-delimited JSON (WAV or raw PCM only), one TranscriptionStreamLine per line. Use POST /v1/transcriptions for anything long. Charged per minute of audio, on duration_seconds.
curl -X POST "https://api.lumavox.ai/v1/stt" \ -H "Authorization: Bearer $API_KEY"Request body (multipart/form-data)
| Field | Type | Required | Description |
|---|---|---|---|
file | string (binary) | Required | The audio. Any container the provider reads. |
stream | boolean | Return newline-delimited JSON instead of one body. Requires WAV or raw PCM. Default false. | |
model | "scribe_v2" | Default "scribe_v2". | |
language | string | The language spoken, as an ISO 639-1 or 639-3 code; unset detects it. 2–8 characters. | |
diarize | boolean | Default false. | |
num_speakers | integer | 1–32. | |
tag_audio_events | boolean | Default false. | |
timestamps | boolean | Return each word and its timing as words. Default false. |
Request body (application/octet-stream)
Responses
| Status | Description |
|---|---|
200 |
application/json, application/x-ndjson — The transcript |
400 |
The multipart body could not be read |
401 |
Missing or invalid credentials |
402 |
Out of credits, or the organisation is suspended — nothing was charged |
403 |
The key is valid but its scopes do not cover this capability — a key limited to tts gets this from /v1/images rather than a 401 |
413 |
The file is larger than 25 MB |
415 |
That content type is not audio, or stream=true was asked of audio it cannot cut |
422 |
The request failed validation |
429 |
Rate limit exceeded |
502 |
The provider failed; the message says why |
503 |
Transcription is not configured on this platform |
200 response body
| Field | Type | Description |
|---|---|---|
text |
string | |
language_code |
string or null | |
language_probability |
number or null | |
duration_seconds |
number | The audio’s length, by the provider’s measure: what is charged |
model |
string | |
words |
array of TranscriptWord or null | Each word and its timing, with timestamps; null otherwise |
words[].text |
string | |
words[].start_seconds |
number or null | When it starts, in seconds from the audio’s start. |
words[].end_seconds |
number or null | When it ends, in seconds from the audio’s start. |
words[].type |
"word", "spacing", "audio_event" or null |
word, the spacing between words, or an audio_event (with tag_audio_events); null when the provider did not say. |
words[].speaker_id |
string or null | Who said it, with diarize; null otherwise. |