Skip to content

Speech to text over REST

Transcribe a finished audio file with the OpenAI-compatible transcriptions endpoint.

POST /v1/audio/transcriptions transcribes a finished audio file in one request. It follows the OpenAI transcriptions shape, so point an existing OpenAI client at it by changing the base URL and the model.

Rhythm and Symphony both transcribe. The examples below use Rhythm; pass symphony in the same model field to use Symphony instead.

Transcribe a file

Upload the audio as multipart/form-data.

curl https://api.sprag.ai/v1/audio/transcriptions \
  -H "Authorization: Bearer $SPRAG_API_KEY" \
  -F [email protected] \
  -F model=rhythm
{
  "text": "Thanks, everyone, for joining. Let us start with the roadmap.",
  "usage": { "input": { "audio": { "duration": "5" } } }
}

usage is abbreviated in the examples on this page. The real object carries a per-modality vector for both the input and output sides, and transcription fills only the input audio duration.

Request fields

FieldRequiredTypeNotes
fileYesfileThe audio to transcribe.
modelYesstringrhythm.
languageNostringISO-639-1 code such as en, not a language name.
response_formatNostringjson (default), verbose_json, text, srt, or vtt. Anything else returns 400.
timestamp_granularities[]Noarrayword, segment, or both. Optional: verbose responses carry both timings without it.
speaker_labelsNobooleanAdds a speaker index to each word. Requires verbose_json, and word in any granularity list you send.
num_speakersNointegerSets the number of speakers for the diarizer. Ignored without speaker_labels.

Rhythm reads aac, aiff, flac, m4a, mp3, ogg, wav, and webm containers. The request body is capped at 100 MiB.

Response fields

json and verbose_json return a JSON object with the fields below. text returns the transcript as a plain text body, and srt and vtt return a rendered caption file, cue times included; all three arrive as text/plain with no JSON fields and no usage record.

FieldTypeWhen it appears
textstringEvery JSON response. The transcript.
usageobjectMeasured per-modality usage and cost. Absent when nothing was measured.
taskstringverbose_json only. Always "transcribe".
durationnumberverbose_json only. Audio duration in seconds.
segmentsarrayverbose_json only. One entry per segment, with start and end times. Present on every verbose response.
wordsarrayverbose_json only. One entry per word, with start and end times. Absent when a granularity list omits word.
languagestringOnly when you sent language. It is an echo of your hint, not a detection result.

The plain json response carries the transcript and the usage record only, with no language and no duration.

Timestamps and speaker labels

Set response_format=verbose_json when you need more than the transcript string. That response adds task, duration, a segments array, and a words array, with start and end times in seconds on every entry.

timestamp_granularities[] takes word and segment, together or alone, and is optional: the verbose response carries both arrays without it. The one list that changes the payload is one that leaves word out, which drops the words array; segments is present on every verbose response.

When captions are the end product, request srt or vtt instead and skip the client-side assembly; the response body is the rendered cue file.

Speaker labels attach to the word objects. Add speaker_labels=true and each attributed word gains a speaker index; num_speakers sets the count the diarizer works to. Diarization needs verbose_json and, if you send a granularity list, word in it; violating either returns 400.

Timestamps and diarization cover the payloads.

Errors

StatusMeaning
400Invalid field, an unsupported response_format, an unknown language code, or audio the decoder cannot read.
401Missing, invalid, or expired credentials.
402No payment method on the account.
403Not a member of the requested organization, or a malformed X-Organization-Id.
404Unknown model id.
413Request body over the 100 MiB cap.
429Rate limit exceeded. Wait Retry-After seconds.
500Unhandled server error.
502Timing or speaker enrichment failed.
503Temporarily unavailable: model cold start, capacity shedding, or an authentication dependency outage. Retry-After is set on the cold-start case.

Full schemas are in the transcriptions reference.