Timestamps
Get word and segment start and end times from a transcript, or a rendered srt or vtt caption file.
Overview
Request the verbose response and the transcript comes back with start and end
times in seconds at two granularities: a words array with one entry per word,
and a segments array with one entry per phrase-length block. Use word timings
when each word needs its own moment, such as karaoke-style highlighting or
jumping to a word in a recording. Use segment timings when you want caption
blocks, since each segment is already a displayable line with a time range.
When captions are the end product, skip the assembly entirely:
response_format=srt or vtt returns a rendered cue file as the response
body.
Timestamps follow the OpenAI verbose_json shape, so a client written against
OpenAI's transcriptions API reads them unchanged.
Request
Send response_format=verbose_json. It is the only field you need: both
timing arrays come back without a granularity list.
curl https://api.sprag.ai/v1/audio/transcriptions \
-H "Authorization: Bearer $SPRAG_API_KEY" \
-F [email protected] \
-F model=rhythm \
-F response_format=verbose_json| Field | Type | Notes |
|---|---|---|
response_format | string | verbose_json for structured timings; srt or vtt for a rendered caption file. |
timestamp_granularities[] | array | Optional. word, segment, or both. A list that omits word drops the words array; segments is present either way. |
Response
The verbose response carries the transcript, the audio duration, and both timing arrays.
{
"text": "Hello from the follow-up test.",
"task": "transcribe",
"duration": 2.0,
"segments": [
{
"id": 0,
"seek": 0,
"start": 0.0,
"end": 2.0,
"text": "Hello from the followup test",
"tokens": [],
"temperature": 0.0,
"avg_logprob": 0.0,
"compression_ratio": 1.0,
"no_speech_prob": 0.0
}
],
"words": [
{ "word": "Hello", "start": 0.0, "end": 0.56 },
{ "word": "from", "start": 0.56, "end": 0.88 },
{ "word": "the", "start": 0.88, "end": 0.96 },
{ "word": "followup", "start": 0.96, "end": 1.6 },
{ "word": "test", "start": 1.6, "end": 2.0 }
],
"usage": { "input": { "audio": { "duration": "2" } } }
}Each words entry is a TranscriptionWord.
| Field | Type | Notes |
|---|---|---|
word | string | The word token. |
start | number | Word start time in seconds. |
end | number | Word end time in seconds. |
speaker | integer | 0-indexed speaker label. Present only where diarization attributed the word. See diarization. |
Each segments entry is a TranscriptionSegment.
| Field | Type | Notes |
|---|---|---|
id | integer | Segment index, starting at 0. |
start | number | Segment start time in seconds. |
end | number | Segment end time in seconds. |
text | string | The text of the segment. |
The remaining segment fields (seek, tokens, temperature, avg_logprob,
compression_ratio, no_speech_prob) exist for OpenAI shape compatibility and
carry placeholder values, so do not branch on them. Segment text can also
differ from the top-level text in punctuation, so display one or the other
rather than mixing them.
Times are seconds from the beginning of the submitted audio, as floats. They are absolute within the file you sent, so if you sliced a longer recording before uploading, add your own offset back.
Timestamps and speaker labels
speaker lives on the word object, so diarization and word timings share a
payload. Send verbose_json with speaker_labels=true to get words carrying
both. Diarization covers that path.
Realtime
Word timings are a REST feature. A
realtime transcription session delivers text through
conversation.item.input_audio_transcription delta and completed events, and
none of its events carry word offsets. If you need timings from live audio, keep
the captured audio and transcribe it again over REST once the turn is done.