Add Captions
/v1/caption-videosCaption a video
fileurltemplateIdrenderwebhookUrlrender.formatstandardrender.frameRate30Form data carries every field as text, so when you send a file pass templateId as a plain number string and render as a json string. Fetching from a url takes an ordinary json body.
curl -X POST "https://api.vsub.io/v1/caption-videos" \
-H "Authorization: Bearer vp_a1b2c3d4e5f60718293a4b5c6d7e8f90a1b2c3d4e5f60718293a4b5c6d7e8f90" \
-F "file=@podcast-clip.mp4" \
-F "templateId=-2"
# or point it at a url instead
curl -X POST "https://api.vsub.io/v1/caption-videos" \
-H "Authorization: Bearer vp_a1b2c3d4e5f60718293a4b5c6d7e8f90a1b2c3d4e5f60718293a4b5c6d7e8f90" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-app.example.com/clips/podcast-clip.mp4",
"templateId": -2,
"webhookUrl": "https://your-app.example.com/hooks/vsub-video"
}'{
"id": "9f0c1d5e-3a1b-4c2f-9d7e-8b1a2c3d4e5f",
"status": "processing",
"render": false,
"createdAt": "2026-08-05T09:20:11.000Z",
"editorUrl": "https://vsub.io/workspace/editor/9f0c1d5e-3a1b-4c2f-9d7e-8b1a2c3d4e5f"
}Uploading and transcribing run in the background. Follow the video with Video status or let a webhook tell you when it's done.
More examples
Captioned and exported in one go
Adding render exports the mp4 as soon as the captions are timed, so the webhook fires once with a finished video rather than with a project waiting in the editor.
{
"url": "https://your-app.example.com/clips/podcast-clip.mp4",
"templateId": -8,
"render": { "frameRate": 60 },
"webhookUrl": "https://your-app.example.com/hooks/vsub-video"
}Everything the request doesn't cover, such as fixing a misheard word, moving the captions or swapping the style, is still yours to change in the editor before rendering. Uploads follow the storage rules of your plan, so on plans where files expire the source video stops resolving after the same number of days as one uploaded in the app.
