Input JSON
{
"operation": "shift",
"from_format": "srt",
"scale": 1.0416666666666667,
"text": "1\n00:00:01,000 --> 00:00:03,000\nWelcome to the workshop.\n\n2\n00:00:04,000 --> 00:00:06,500\nCheck the label before washing.\n"
}
Attest tools · Subtitle tools: convert, retime, merge and read caption files
Stretch subtitle timings by 25/24 to match a clip slowed from 25 fps to 24 fps.
{
"operation": "shift",
"from_format": "srt",
"scale": 1.0416666666666667,
"text": "1\n00:00:01,000 --> 00:00:03,000\nWelcome to the workshop.\n\n2\n00:00:04,000 --> 00:00:06,500\nCheck the label before washing.\n"
}{
"operation": "shift",
"from_format": "srt",
"to_format": "srt",
"cues": 2,
"duration_seconds": 6.771,
"result_text": "1\n00:00:01,042 --> 00:00:03,125\nWelcome to the workshop.\n\n2\n00:00:04,167 --> 00:00:06,771\nCheck the label before washing.\n",
"truncated": false,
"applied": {
"offset_seconds": 0,
"scale": 1.0416666666666667,
"merge_gap_seconds": null,
"strip_tags": false,
"files": 1
},
"info": {
"cues": 2,
"characters": 55,
"words": 9,
"lines": 2,
"first_start_seconds": 1.042,
"last_end_seconds": 6.771,
"total_cue_seconds": 4.687,
"coverage_ratio": 0.8181,
"longest_cue_seconds": 2.604,
"shortest_cue_seconds": 2.083,
"max_characters_per_line": 31,
"max_characters_per_second": 10.4,
"overlapping_cues": 0,
"zero_length_cues": 0
},
"warnings": [],
"limits": {
"max_file_bytes": 4194304,
"max_file_base64_characters": 5592408,
"max_text_characters": 4000000,
"max_files": 20,
"max_total_bytes": 8388608,
"max_cues": 200000,
"max_result_bytes": 2000000,
"max_fetch_seconds": 120
},
"sources": [
{
"name": "W3C WebVTT: The Web Video Text Tracks Format",
"url": "https://www.w3.org/TR/webvtt1/",
"used_for": "WebVTT parsing and writing: the header, NOTE, STYLE and REGION blocks, cue identifiers, cue settings, the timestamp grammar and the cue payload tags"
},
{
"name": "SubRip (.srt) — a de facto format with no published specification; the shape used here is the one every player accepts",
"url": "https://en.wikipedia.org/wiki/SubRip",
"used_for": "SubRip parsing and writing"
},
{
"name": "Advanced SubStation Alpha (.ass/.ssa) — community specification, with the override tag list from the Aegisub manual",
"url": "https://aegisub.org/docs/latest/ass_tags/",
"used_for": "reading [Events] Dialogue lines, their H:MM:SS.cc timings and the \\N, \\n, \\h, \\i, \\b, \\u, \\p and \\r override tags"
},
{
"name": "YouTube SBV (.sbv) — the caption format YouTube exports, H:MM:SS.mmm start and end joined by a comma",
"url": "https://support.google.com/youtube/answer/2734698",
"used_for": "SBV parsing"
}
],
"notice": "General information about the subtitle file you supplied. Timings are read from the file and transformed exactly as requested; nothing here checks the file against the video it belongs to. The file is processed in memory and is not stored.",
"checked_at": "2026-10-20T20:47:48.843Z"
}curl -s -X POST https://getattest.com.au/api/v1/subtitles \
-H "authorization: Bearer $ATTEST_API_KEY" \
-H "content-type: application/json" \
--data-raw '{"operation":"shift","from_format":"srt","scale":1.0416666666666667,"text":"1\n00:00:01,000 --> 00:00:03,000\nWelcome to the workshop.\n\n2\n00:00:04,000 --> 00:00:06,500\nCheck the label before washing.\n"}'Run this call with your own bearer key. Issue an API key.
The input was validated and run locally through the registered service. The output above is a display preview of the captured service result. File bytes are described instead of printed, and strings longer than 400 characters are truncated; the HTTP API also adds call_id, credits_charged and credits_remaining. Timestamps and generated identifiers will vary.
Source: apps/api/svc/subtitle_tools.mjs