How to generate an SRT file from a video
To generate an SRT file from a video, transcribe it with timestamps and write each timed sentence as a numbered block. Sume's STT returns timed JSON.

To generate an SRT file from a video, transcribe its speech with timestamps and write each line as a numbered block: the number, a start --> end timing line, and the text. Sume's speech-to-text returns JSON rather than an .srt file, but it holds what an SRT needs: ask for sentence segmentation and you get segments[], each with text, start, and end in seconds, one block per segment.
Sume facts come from the Video inspect docs and the STT 1.0 schema in the Sume API reference, read on 2026-09-27. The SRT layout itself is the plain-text subtitle format, not a Sume feature. For the raw transcript fields, see speech-to-text with word timestamps.
How do I get timed sentences from the video?
Two Sume calls return timed sentences, and both take segmentation: { "mode": "sentence" } plus an optional language_code hint (omit it for auto-detect):
| Video inspect | STT 1.0 | |
|---|---|---|
| Route | POST /v1/video-inspect with transcribe: true | POST /v1/stt-1.0/transcribe |
| Input | video_url: a media.sume.com clip in your workspace, such as an earlier Sume job's output | audio_url: a public HTTPS audio file, such as the video's soundtrack |
| Word times | Seconds from the start of the video | Seconds from the start of the audio |
| Where segments land | The inspect's transcript.segments[] | segments[] on the job result |
| Billing | Probe and stills unbilled; the transcript bills at the STT 1.0 rate | The STT 1.0 rate |
curl -X POST https://api.sume.com/v1/video-inspect \
-H "Authorization: Bearer $SUME_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: srt-transcript-001" \
-d '{
"video_url": "https://media.sume.com/artifacts/artf_demo/talk.mp4",
"frames": false,
"transcribe": true,
"segmentation": { "mode": "sentence" }
}'How do I write the SRT file from the segments?
Inspect waits up to 30 seconds by default and answers 200 with the finished inspect, or 202 with a job to poll; read it later with GET /v1/video-inspect/:id. Then write one block per segment:
- Number the blocks 1, 2, 3 in order. STT 1.0 numbers its segments from zero.
- Write each time as
HH:MM:SS,mmm, with a comma before the milliseconds. - Put the timing line under the number, the text under it, and a blank line after each block.
- Segments are gapless: each one ends where the next begins, so a line stays up through a pause. To end a block at the last spoken word instead, take that word's
endfromwords[].
def timecode(t):
ms = round(t * 1000)
h, ms = divmod(ms, 3_600_000)
m, ms = divmod(ms, 60_000)
s, ms = divmod(ms, 1000)
return f"{h:02}:{m:02}:{s:02},{ms:03}"
def segments_to_srt(segments):
blocks = []
for n, seg in enumerate(segments, start=1):
times = f"{timecode(seg['start'])} --> {timecode(seg['end'])}"
blocks.append(f"{n}\n{times}\n{seg['text'].strip()}\n")
return "\n".join(blocks)Can I make a WebVTT file instead?
Yes, from the same segments. A WebVTT file starts with a WEBVTT line and a blank line, writes the milliseconds after a period instead of a comma, and does not need the block numbers. Everything else in the loop stays the same.
To burn the lines into the picture instead of shipping a separate file, send them as cues, as in burn an SRT file into a video.
What does it cost, and what are the limits?
- The transcript bills at the STT 1.0 rate, $0.01 per audio minute on API pricing, plus a 5.5% agent fee by default. An inspect's probe and stills are unbilled.
- Without
duration_seconds, a transcript reserves 1 minute; the hint tops out at 600 seconds. Inspect reads sources up to 1,800 seconds. - A clip with no audio track fails inspect with
inspect_source_has_no_audio. Checkprobe.has_audiofirst with aframes: falseinspect. - The transcript comes back as JSON fields, not as a subtitle file. A caption job does not hand back its transcript either: raw transcripts are not part of that resource's public contract.
Sources
Related posts
More in Media tools
- How to check a video's bitrate from its size and length
Check a video's average bitrate: size in bytes × 8 ÷ length in seconds. Sume's free probe returns both numbers, size_bytes and duration_seconds.
- How to increase video length by looping a short clip
Loop a short clip until it matches a song or voiceover: put it in one Timeline 1.0 slot as long as the audio and set render.pad_mode to loop.
- Instagram story ad size: 9:16 specs, plus Facebook Stories
Meta recommends 9:16 at 1440×2560 for Instagram and Facebook Stories ads. Lengths that play in full, safe zones, and how to make one with Sume.
- Instagram Reels video requirements for API uploads
Instagram's API cURLs a Reel from a public video_url: MP4 or MOV, H.264 or HEVC, 23–60 fps, 3 s to 15 min, 300 MB. How a Sume MP4 maps to each rule.
Written by Sume