> ## Documentation Index
> Fetch the complete documentation index at: https://docs.captioncraft.studio/llms.txt
> Use this file to discover all available pages before exploring further.

# Media requirements

> Prepare a source video the API can download and caption.

## Video limits

| Property           | Limit                                                                 |
| ------------------ | --------------------------------------------------------------------- |
| Source formats     | MP4, MOV, WebM                                                        |
| Maximum file size  | 500 MiB (524,288,000 bytes)                                           |
| Maximum duration   | 600 seconds                                                           |
| Maximum dimensions | Long edge ≤ 1920 pixels and short edge ≤ 1080 pixels                  |
| Audio              | An audio track containing speech is required unless `srt` is provided |
| Output             | MP4 video, SRT subtitles, JSON transcript                             |

Both 1920 × 1080 landscape and 1080 × 1920 portrait videos are supported. A square video must fit within 1080 × 1080. Odd pixel dimensions may be rounded down by one pixel during encoding.

The API inspects the video automatically. Videos longer than 600 seconds fail validation; the API does not trim them. Credits are reserved for the actual duration rounded up to a whole second before caption preparation starts.

## Use an existing SRT file

Include the file's text in the optional `srt` JSON field of `POST /v1/subtitles`. This skips ElevenLabs transcription entirely, so the video may have no audio. The `language` field is ignored when `srt` is present.

```json theme={"system"}
{
  "video_url": "https://your-cdn.example/video.mp4",
  "preset": "highlight",
  "srt": "1\n00:00:00,000 --> 00:00:02,000\nHello world!\n\n2\n00:00:02,000 --> 00:00:04,000\nYour own captions.\n"
}
```

To read a local file into the request safely, use `jq --rawfile`:

```bash theme={"system"}
jq -n --arg video_url "$VIDEO_URL" --rawfile srt captions.srt \
  '{video_url: $video_url, srt: $srt, preset: "highlight"}' |
  curl --fail-with-body "$CAPTIONCRAFT_API_URL/v1/subtitles" \
    -H "Authorization: Bearer $CAPTIONCRAFT_API_KEY" \
    -H "Content-Type: application/json" --data-binary @-
```

Use numbered, non-empty cues separated by blank lines, ordered by start time, with `HH:MM:SS,mmm --> HH:MM:SS,mmm` timestamps. UTF-8 text, a BOM, multiline captions, and LF or CRLF line endings are accepted. The SRT limit is 256 KiB UTF-8 and 8192 words; the full JSON body may be up to 512 KiB. Supply file contents, not a URL or base64 data. Empty or malformed SRT returns `400 INVALID_REQUEST`.

Cue times must fit within the source video. A job whose cues extend beyond the inspected duration fails with `INVALID_SRT` and releases its reserved credits. The SRT download preserves the supplied file contents. Rendered captions keep cue boundaries, with wrapping and splitting determined by the selected preset. Basic SRT formatting tags are removed from rendered text in favor of the preset's styling. Since SRT has no word timings, animated captions and the JSON transcript use word timings estimated evenly within each cue.

Billing remains based on the video duration, rounded up to whole seconds.

## Direct HTTPS URLs

The API downloads `video_url` from the processing server. The URL must:

* Use HTTPS on the standard port, with a public hostname.
* Return the video directly with HTTP `200` and no redirect.
* Be reachable without cookies or additional authorization headers.
* Contain no embedded username/password or URL fragment.
* Remain valid while the job is waiting and downloading.

Signed object-storage URLs are supported when they meet these requirements. Account for queue time when choosing their expiration.

URLs for local networks, localhost, private addresses, and custom ports are rejected. A YouTube page, a cloud-drive sharing page, or a login page is not a direct media URL.

## Uploads

There is no public upload endpoint in this release. Upload your media to your own object storage, then provide its direct HTTPS URL.

## Transcript format

The downloaded JSON transcript contains the full text and individual words:

```json theme={"system"}
{
  "text": "Make every word count.",
  "timestamp_unit": "seconds",
  "words": [
    { "text": "Make", "start": 0.12, "end": 0.4 },
    { "text": "every", "start": 0.42, "end": 0.75 },
    { "text": "word", "start": 0.78, "end": 1.08 },
    { "text": "count.", "start": 1.1, "end": 1.5 }
  ]
}
```

Times are measured in **seconds**, not milliseconds, from the start of the source video. The example timestamps above are illustrative.
