---
title: Make an SRT captions file for an LMS
description: Get an SRT or VTT subtitles file for your training video, with words you checked on the timeline, ready to upload to your LMS.
---
Get a captions file for your learning platform: an SRT file, a VTT file, subtitles your LMS shows as closed captions. Your agent transcribes the video, puts the captions on the timeline so you can fix any word, then reads the caption slides back and writes the file. The video itself stays clean, with no captions burned in, unless you want them.

Use invideo for this when you want to correct the captions by eye on the timeline first, and get the same words as a sidecar file and, if you like, burned into the video.

## Quickest path

Set up your agent first with [invideo for AI agents](/agents). Then give it this prompt.

```text
Make an SRT captions file for this training video <edit-url>.
Transcribe it, put the captions on the timeline on a branch so I can fix
words, then write lesson-01.srt from the caption slides. Keep each caption
short. Export the video without the captions burned in.
```

In a chat app, the agent gives you the SRT text to save. In a terminal, it writes the file into your folder.

## What you need

These are the inputs and the choices.

- The video, on an invideo timeline or as a file.
- The format your LMS takes: SRT or VTT. Most take both.
- Words that the transcript may get wrong: names, product terms, acronyms.
- Burned-in captions as well, or the sidecar file only.

## Steps

The timeline is where you check the words. The file comes from the timeline.

<Steps>
<Step title="Transcribe the video">
The agent prices `audio.transcript` with `dry_run` on the video's sequence URL from `add_media` and tells you the price. For a price of 1 credit or more it waits for your yes. Then it starts the transcript with `max_credits` set to that price, and calls again after `retry_after_s` for the words. It sees every word with its time and speaker.
</Step>
<Step title="Put the captions on the timeline">
The agent creates a branch with `timeline_history`, then groups the words into short slides and adds them with `add_captions`, with `slides` and `words`. It sees a caption clip in `get_timeline`.
</Step>
<Step title="Fix the words">
The agent fixes each wrong word you or the terms list point to with `set_caption_slide_text`, and a slide's edges with `trim_caption_slide`. It sees the new text with the word times kept.
</Step>
<Step title="Read the caption slides back">
The agent calls `get_timeline` with mode `collection` and collection `caption_slide`. It pages with `next_offset` and the same `snapshot` until it has every slide. It sees each slide's text and its start and end.
</Step>
<Step title="Write the file">
The agent turns each slide into one numbered cue and writes the SRT or VTT file itself. Times in a read are rational, `{value, rate}`, which is `value / rate` seconds. It sees a file that starts at cue 1 and has no overlaps.
</Step>
<Step title="Export the video">
The agent turns the caption clip off with `set_clip_enabled`, then calls `export`. For burned-in captions too, it exports once more with the clip on. It sees an export card with status `completed`.
</Step>
</Steps>

The terminal version:

```bash
invideo media audio.transcript <sequence-url> --dry-run
invideo media audio.transcript <sequence-url> --max-credits <price>
invideo edit show <edit-url> --json
invideo branch new <edit-url> --name captions --token <state_token>
invideo edit show <branch-url> --json
invideo edit change <branch-url> --timeline T1 --token <state_token> \
  --operations @captions.json
invideo edit show <branch-url> --mode collection \
  --collection caption_slide --json > slides.json
invideo edit export <branch-url> --format video --quality 1080 --json
invideo status <card-url> --wait
invideo notebook show <card-url> --out ./out
```

Where each value comes from:

- `<sequence-url>` is the video's `url` from `invideo asset upload`, a `…/notebook/seq-N.M` URL.
- `<price>` is the dry run's `.estimated_credits`.
- `<edit-url>` is the video's timeline URL, from `invideo edit new` or the editor. `<state_token>` comes from `invideo edit show <edit-url>` for `branch new`.
- `<branch-url>` is the `branch_url` that `invideo branch new` returns. After that, `<state_token>` comes from `invideo edit show <branch-url>`, read again before each change, because the main token is stale on the branch.
- `<card-url>` is `.sequences[0]` of the export answer. `invideo status` waits but saves nothing. `invideo notebook show` saves the video as `./out/export.mp4`, and the agent renames it.

The file behind `@captions.json` is the bare list of ops that `--operations` takes. It adds the caption clip with its first slides. `start_f` and `end_f` are frames at the timeline's frame rate.

```json
[
  { "op": "add_captions", "track": "V3", "slides": [
    { "text": "Welcome to the safety course.",
      "start_f": 0, "end_f": 75 },
    { "text": "First, find your nearest exit.",
      "start_f": 84, "end_f": 165 }
  ] }
]
```

The SRT file the agent writes from those slides:

```text
1
00:00:00,000 --> 00:00:02,500
Welcome to the safety course.

2
00:00:02,800 --> 00:00:05,500
First, find your nearest exit.
```

A VTT file starts with a `WEBVTT` line, and its times use a full stop before the milliseconds.

## Cost and time

Edits and exports are free. Generation and transcripts cost credits. Paid stock costs a small credit charge, or one of your workspace's iStock licenses. Your agent runs a dry run first and tells you the price before it spends anything.

- Costs credits: the transcript, once per file.
- Free: the caption clip, every fix, reading the slides, writing the file, `export`.

The file takes a few minutes after the transcript is ready. Your word check takes the longest. See [Credits](/account/credits) for prices.

## If something goes wrong

Most problems are times or missing slides.

| Symptom | Fix |
| --- | --- |
| `audio.transcript` refused with `code: "not_found"`, or CLI exit 2 | The call named a media bin asset. Pass the video's sequence URL from `add_media` or `invideo asset upload`. |
| CLI exit 3 on the first change after `invideo branch new` | The main token is stale on the branch. Run `invideo edit show <branch-url>` and use its `state_token`. |
| `invideo status --wait` ends and the folder is empty | `status` does not download. Run `invideo notebook show <card-url> --out <dir>`. |
| The SRT is missing the end | The read was paged. Continue with `next_offset` and the same `snapshot`. |
| A `snapshot` is refused | The timeline changed. Read again from the first page. |
| A word is timed wrong | Split or join the timed pieces with `split_caption_fragment` and `merge_caption_fragment`. |
| Captions are early or late in the LMS | The caption clip starts later than the video. Times in the file are timeline times, so export from the same start. |
| Cues overlap | Two slides share frames. Trim one with `trim_caption_slide`, then read again. |
| The LMS rejects the file | Check the format: SRT uses a comma before milliseconds, VTT a full stop and a `WEBVTT` first line. |
| `set_text` refused on captions | That caption clip has several slides. Use `set_caption_slide_text`. |
| Avoid: write the file from the raw transcript | Instead: write it from the caption slides, which hold your fixes. |

## Prompts to try

Each prompt is a real variation of this job.

```text
Write VTT captions for every lesson in this project, one file per
lesson, named after each timeline.
```

```text
Make English and Spanish SRT files for this video. Translate the English
caption slides line by line and keep the same times.
```

```text
Burn the captions into the video in white on a dark bar, and also give me
the SRT file.
```

## When to use something else

invideo does not write SCC files, the broadcast caption format. Convert the SRT with a captioning tool such as Subtitle Edit. Uploading the file is done in your LMS, in the video's caption or subtitle settings. For legal caption quality on public content, see [Make closed captions and audio description for ADA Title II and Section 508](/how-to/training/captions-for-ada-508).

## Related

- [Make closed captions and audio description for ADA Title II and Section 508](/how-to/training/captions-for-ada-508)
- [Add word-by-word captions](/how-to/creators/word-by-word-captions)
- [Turn a syllabus into a course of lesson videos](/how-to/training/online-course)
- [Use Whisper timings with invideo](/integrations/whisper)
- [Timeline edit operations](/reference/edit-operations)