Skip to content

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
FieldTypeNotes
response_formatstringverbose_json for structured timings; srt or vtt for a rendered caption file.
timestamp_granularities[]arrayOptional. 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.

FieldTypeNotes
wordstringThe word token.
startnumberWord start time in seconds.
endnumberWord end time in seconds.
speakerinteger0-indexed speaker label. Present only where diarization attributed the word. See diarization.

Each segments entry is a TranscriptionSegment.

FieldTypeNotes
idintegerSegment index, starting at 0.
startnumberSegment start time in seconds.
endnumberSegment end time in seconds.
textstringThe 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.