How to burn an SRT file into a video

Burning an SRT file draws its lines into the picture. Sume's captions API takes no .srt file, so turn each block into a cue and send the cues instead.

5 min readSume
All posts

To burn an SRT file into a video, draw each subtitle block into the frames between its two timecodes, so the text becomes part of the picture and shows on every player. Sume's captions API does this, but it does not take the .srt file itself: turn each block into a cue with text, start, and end in seconds, then send the cues with the video's URL to POST /v1/video-captions. Cues skip speech-to-text, so Sume burns exactly your lines at your times.

Sume details come from the Video captions docs and the caption schema in the Sume API reference, read on 2026-09-27; details marked as current code are read from Sume's code. Whether to burn at all is covered in hard subtitles vs soft subtitles.

How do I turn SRT blocks into cues?

An SRT block is a sequence number, a timing line such as 00:00:01,000 --> 00:00:03,500, and one or more lines of text. Each block becomes one cue:

  • Drop the sequence number. A cue takes only text, start, and end.
  • Convert both timecodes to seconds: hours × 3600, plus minutes × 60, plus seconds, with the milliseconds after the comma as decimals. 00:00:03,500 becomes 3.5.
  • Join a block's text lines with a newline: the docs allow one in a cue's text for a two-line card. In current code the default Latin style, slam, ignores the break and draws the words in capitals.
  • Strip SRT formatting tags such as <i>; the docs define no markup for cue text.
import re

TIME = r"(\d+):(\d\d):(\d\d)[,.](\d{3})"

def seconds(h, m, s, ms):
    return int(h) * 3600 + int(m) * 60 + int(s) + int(ms) / 1000

def srt_to_cues(srt_text):
    cues = []
    for block in re.split(r"\n\s*\n", srt_text.strip()):
        lines = block.strip().splitlines()
        timing = next(i for i, line in enumerate(lines) if "-->" in line)
        start, end = re.findall(TIME, lines[timing])[:2]
        text = re.sub(r"<[^>]+>", "", "\n".join(lines[timing + 1 :])).strip()
        cues.append({"text": text, "start": seconds(*start), "end": seconds(*end)})
    return cues

How do I send the cues to Sume?

Send the video's public HTTPS URL as video_url and the list as cues (segments is an alias). cues cannot be combined with words, segments, or script_text. Add an Idempotency-Key: if the request times out, resending it with the same key and the same body returns the original job instead of a second one.

Omit style and the wording picks it: slam for Latin text, black-outline for Korean. A style you name is rendered as named, but Korean lines on slam, punch, or tiktok-green are refused with 400 caption_hangul_text_latin_style. To move the lines up or down, see customize burned-in captions.

For Korean lines, add "design": { "phrasing": { "max_words": 1 } }. In current code black-outline and the other Hangul phrase-card styles merge short cues 0.45 seconds or less apart into one card of up to 22 characters, so a line can appear before its start; a limit of one keeps each cue on its own card.

curl -X POST https://api.sume.com/v1/video-captions \
  -H "Authorization: Bearer $SUME_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: srt-burn-001" \
  -d '{
    "video_url": "https://example.com/clip.mp4",
    "cues": [
      { "text": "Welcome to the tour.", "start": 1.0, "end": 3.5 },
      { "text": "Setup takes one minute.", "start": 3.5, "end": 6.2 }
    ]
  }'

What are the limits?

Check the file against these before you send it. A longer subtitle file does not fit in one job.

From Video captions and the Sume API reference, read 2026-09-27. The end rule and the length and audio rows are current code behavior.
RuleLimit
Cues per job1 to 200
Cue text1 to 400 characters
Cue start and end0 to 60 seconds, with end greater than start
video_urlA fetchable public HTTPS video. Localhost, private-network, non-HTTPS, and signed or private URLs are rejected
Source length60 seconds or less; a longer source fails with duration_out_of_range
Source audioThe video needs an audio stream, even with cues; one without fails with missing_audio_stream
SRT uploadNot supported; send the lines as cues

What if my video is longer than 60 seconds?

Split it. Cut the video into chunks of 60 seconds or less, between SRT blocks rather than inside one. Give each chunk the cues that fall inside it, with the chunk's start time subtracted from every start and end, then rejoin the captioned chunks. Add captions to a long video walks through the cut and the rejoin. Sume's cutting and joining tools read only videos already on media.sume.com in your workspace, such as an earlier Sume job's output.

How do I get the result, and what does it cost?

Poll GET /v1/jobs/:id/status until it is terminal, then read the captioned video_url from GET /v1/video-captions/:id. Each accepted standalone caption job reserves and captures the fixed amount listed on the Video captions page, for videos up to 60 seconds; the docs say to confirm live pricing in GET /v1/catalog. The submit response quotes the job's amount as usage.billable_amount_usd.

Sources

Related posts

More in Media tools

All Media tools posts

Written by Sume