Bearer key · JSON
POST /api/v1/subtitles
curl -s -X POST https://getattest.com.au/api/v1/subtitles \
-H "authorization: Bearer $ATTEST_API_KEY" \
-H "content-type: application/json" \
-d '{"operation":"convert","to_format":"vtt","text":"1\n00:00:01,000 --> 00:00:03,500\nHello there.\n"}'
Send the key as a bearer token in the authorization header. One key and one credit balance cover every service, including Attest Capture. A failed call is refunded automatically. No key yet? POST /api/v1/keys issues one with 25 free credits and no signup — see the key guide.
Captured 2026-09-21
Example
This request was run against the running service on 2026-09-21 and the response below is what came back, unedited.
Request JSON
{
"operation": "convert",
"to_format": "vtt",
"text": "1\n00:00:01,000 --> 00:00:03,500\nHello there.\n"
}
Captured response JSON
{
"call_id": "3b3ddb5c-1d57-4066-9b8f-98f853e6dbd7",
"operation": "convert",
"from_format": "srt",
"to_format": "vtt",
"cues": 1,
"duration_seconds": 3.5,
"result_text": "WEBVTT\n\n1\n00:00:01.000 --> 00:00:03.500\nHello there.\n",
"truncated": false,
"applied": {
"offset_seconds": 0,
"scale": 1,
"merge_gap_seconds": null,
"strip_tags": false,
"files": 1
},
"info": {
"cues": 1,
"characters": 12,
"words": 2,
"lines": 1,
"first_start_seconds": 1,
"last_end_seconds": 3.5,
"total_cue_seconds": 2.5,
"coverage_ratio": 1,
"longest_cue_seconds": 2.5,
"shortest_cue_seconds": 2.5,
"max_characters_per_line": 12,
"max_characters_per_second": 4.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-09-20T16:55:57.516Z",
"credits_charged": 1,
"credits_remaining": 9989
}
For agents
Use when
Use this when a task involves a subtitle or caption file: converting between SubRip (.srt), WebVTT (.vtt), ASS/SSA and YouTube SBV, shifting timings or rescaling them for a frame-rate change (23.976 to 25 and back), merging several files onto one timeline, pulling a plain-text transcript out of captions, or reporting a file's cue count, duration and reading speed. The converted file comes back in result_text; the info operation leaves result_text empty and answers in the info block. Send the file as text, as a public URL, or as base64 up to 4 MB.
11 fields
Input
Scroll the table horizontally to see all fields.
Field / Type / Required / What it does| Field | Type | Required | What it does |
|---|
operation | string | Optional | convert (default), shift, merge, to_text or info. |
|---|
text | string | Optional | The caption file as text. Not allowed with operation merge. |
|---|
url | string | Optional | A public http(s) URL to read the caption file from. |
|---|
file_base64 | string | Optional | The caption file as base64, up to 4 MB. |
|---|
files | array | Optional | The files to merge onto one timeline. merge only. |
|---|
from_format | string | Optional | auto (default), srt, vtt, ass or sbv. |
|---|
to_format | string | Optional | srt, vtt, ass or sbv. Required for convert; refused for info and to_text. |
|---|
offset_seconds | number | Optional | Seconds to shift every cue, for operation shift. |
|---|
scale | number | Optional | Timing multiplier for a frame-rate change, for operation shift. |
|---|
merge_gap_seconds | number | Optional | Gap to leave between files, for operation merge. |
|---|
strip_tags | boolean | Optional | Drop styling tags from the cue text. |
|---|
HTTP 200
Response
Every successful response also carries call_id (your receipt for the charge), credits_charged and credits_remaining.
Scroll the table horizontally to see all fields.
Field / What it holds| Field | What it holds |
|---|
operation | The operation that ran. |
|---|
from_format | The format the file was read as. |
|---|
to_format | The format written, or null for info and to_text. |
|---|
cues | Cue count. |
|---|
duration_seconds | Where the last cue ends. |
|---|
result_text | The converted file, the transcript, or empty for operation info. |
|---|
truncated | Whether the output stopped at a cap. |
|---|
applied | The offset, scale, merge gap, tag stripping and file count actually applied. |
|---|
info | Cue count, duration and reading speed. |
|---|
warnings | What the parser had to repair or drop. |
|---|
limits | The caps that applied. |
|---|
sources | The format specifications this parser and writer follow. |
|---|
Machine-readable failures
Errors
Errors return JSON such as {"error":"invalid_api_key"}. A failed call is refunded automatically.
Scroll the table horizontally to see all fields.
Code / Status / Meaning| Code | Status | Meaning |
|---|
text_required | 400 | None of text, url or file_base64 was sent. |
|---|
conflicting_input | 400 | merge was sent text, url or file_base64 instead of files. |
|---|
files_not_allowed | 400 | files was sent to an operation other than merge. |
|---|
files_required | 400 | merge was called without files. |
|---|
too_few_files | 400 | merge needs more than one file. |
|---|
to_format_required | 400 | convert was called without to_format. |
|---|
to_format_not_allowed | 400 | to_format was sent to info or to_text, which write no file. |
|---|
invalid_to_format | 400 | to_format is not srt, vtt, ass or sbv. |
|---|
offset_or_scale_required | 400 | shift was called with no offset and no scale. |
|---|
unknown_subtitle_format | 400 | The file is not a caption format this service reads. |
|---|
too_many_cues | 400 | The file has more cues than the cap. |
|---|
input_too_large | 400 | The input is past the byte cap. |
|---|
fetch_failed | 502 | The URL did not answer. Not charged. |
|---|
On every service
Scroll the table horizontally to see all fields.
Code / Status / Meaning| Code | Status | Meaning |
|---|
invalid_api_key | 401 | The authorization header is missing or the key is unknown. |
|---|
insufficient_credits | 402 | The balance is below this call's cost. The response carries credits_required and credits_remaining. |
|---|
rate_limit_exceeded | 429 | Free keys share 10 calls a minute across every service. The response carries limit and window_seconds. |
|---|
services_unavailable | 503 | The credit store could not be reached. Retry once after 30 seconds. |
|---|
6 worked examples
Examples
Where the answer comes from
Source and scope
Written against the W3C WebVTT specification, the de facto SubRip format, the community Advanced SubStation Alpha specification and YouTube's SBV format; each response lists them in sources.
Attest reports what it read, with the source it read it from. It is general information, not advice, and not a legal record.
All Attest tools · Service list as JSON · OpenAPI