2026-09-25 · 8 min read
AI captions API: add word-timed captions to any video with one POST
If you build anything that ships short-form video at volume - a UGC pipeline, a clipping tool, an agent that posts to social - captions stop being a nice-to-have the moment you look at retention. Most feeds autoplay muted, so the words on screen carry the message. The question is not whether to caption. It is whether captioning is a manual step someone does in an editor, or an API call your pipeline makes on its own.
This post is about the API approach: what an AI captions API actually does under the hood, the honest trade-offs against the alternatives, and a working integration you can copy.
What an AI captions API actually does
A captions API chains four steps that used to be separate tools. First, speech-to-text with word-level timestamps - not just what was said, but exactly when each word starts and ends. Second, grouping those words into caption blocks that respect reading speed and screen space. Third, styling: typeface, size, color, the active-word highlight you see all over short-form video. Fourth, rendering the styled text into the video itself, so the output is a plain MP4 that looks identical in every player, app, and feed.
That last step - burning captions into the pixels - is what separates this from subtitle files. A WebVTT or TTML sidecar (both W3C specs) only works where the player chooses to render it, with whatever styling the player feels like. Burned-in captions survive reposts, re-encodes, and every platform's player, and they can do the karaoke-style word highlight that sidecar formats cannot express.
The alternatives, honestly
FFmpeg can burn subtitles from an ASS file, and for a one-off video it works fine. The friction shows up at volume: you still have to generate word-level timing yourself, hand-tune ASS styling, manage fonts on every worker, and babysit render jobs. You end up building the API you did not want to buy.
Editor-first tools like captions.ai are good products aimed at a different job: a human polishing one video at a time in a GUI. If your videos are produced by other software, a UI is a bottleneck, not a feature. And player-side VTT tracks fail the moment your clip leaves a player you control - which is the entire point of social distribution.
The caption.sh API in practice
caption.sh is built for the programmatic case. It is an async job API: one POST creates a job, you poll (or get a webhook), and you download a captioned MP4. Pull a video straight from a URL:
curl -X POST https://api.caption.sh/v1/videos \
-H "Authorization: Bearer $CAPTION_API_KEY" \
-H "Content-Type: application/json" \
-d '{"source_url": "https://example.com/raw.mp4"}'
# -> 202 { "job_id": "..." }
# poll GET /v1/jobs/{id} until status is "done",
# then GET /v1/jobs/{id}/result for the MP4Uploading a file instead is a two-step flow: the same POST returns a signed upload URL, you PUT the bytes to it (no auth header needed - the URL is the credential), and the job starts automatically when the upload lands. Retries are safe with an Idempotency-Key header. Failed renders never charge: billing is prepaid at $0.10 per minute of video, debited only on real render time, and a 402 tells you to top up before a job starts.
Styling is data, not a design tool
Every style choice is a field in the options object, and every field has a default that looks decent, so the zero-config call above already produces a clean result. When you do care, the knobs map directly to how short-form captions actually look:
- font: 18 bundled typefaces (luckiest-guy, inter, dynapuff, black-ops-one, ...) - no font files to manage
- max_words and max_lines: how many words per caption group and how tall the block may wrap
- highlight + highlight_color: the active word gets its own color as it is spoken (default #00E676)
- decoration: outline stroke or rounded backdrop box, with opacity and corner radius, so text stays legible on any footage
- position: top, center, bottom, or an exact fraction of frame height
- max_tilt: random per-caption rotation for the hand-placed look; censor_captions and censor_audio for brand safety
Sizes are fractions of the video height, not pixels, so the same options produce proportional captions on vertical, square, and landscape sources. That one detail removes a whole class of per-aspect-ratio bugs.
If your consumer is an agent
caption.sh also ships a hosted MCP server at https://mcp.caption.sh/mcp (streamable HTTP, same API key as the bearer token). Agents in Claude, Cursor, and other MCP clients get caption_video, get_caption_job, list_caption_styles, list_caption_jobs, and get_caption_balance as native tools, plus nine ready-made style recipes. An agent that can browse a drive of raw clips can caption all of them without anyone writing orchestration code.
Try it
The fastest way to judge the output is the playground on caption.sh - drop a video, tweak the style JSON, watch the preview update. From there, grab an API key from the dashboard and the quickstart above is the whole integration. The full API reference lives at caption.sh/docs.