Subclip Logo

API Reference

Viral Captions API

Upload one video, optionally upload an SRT file, choose a viral caption template, and Subclip renders a final MP4 with animated captions.

Simple rule: if you upload SRT, Subclip uses it. If you do not upload SRT, Subclip runs ASR on the video audio using the selected language.

For current credit costs, see API credit costs.

OpenAPI-style reference

API endpoints

Render uploaded videos with viral caption templates, optional SRT input, and face tracking.

API v1 storage handling: files uploaded or generated through /api/v1 are auto-cleaned and do not count toward the user's storage quota.
POST/api/v1/dynamic-captions/uploads

Create signed upload URLs

Creates upload URLs for the source video and optional SRT file.

Bearer auth

Parameters

FieldTypeRequiredDetails
projectNamestringNo
Optional project name
body
video.fileNamestringYes
Video file name
body
video.contentTypestringYes
video/mp4, video/webm, video/quicktime, video/mpeg, or video/x-matroska
body
video.fileSizenumberYes
Declared source video size in bytes, max 5GB
body
srt.fileNamestringNo
Optional SRT file name
body
srt.fileSizenumberNo
Optional SRT size in bytes, max 2MB
body

Examples

Request

{
  "projectName": "Captioned reel",
  "video": {
    "fileName": "source.mp4",
    "contentType": "video/mp4",
    "fileSize": 52428800
  },
  "srt": {
    "fileName": "source.srt",
    "contentType": "text/plain",
    "fileSize": 18432
  }
}

Response

{
  "projectId": "dcproj_...",
  "uploadExpiresIn": 900,
  "video": {
    "uploadUrl": "https://...",
    "objectKey": "user_.../dynamic-captions/dcproj_.../video-...mp4"
  },
  "srt": {
    "uploadUrl": "https://...",
    "objectKey": "user_.../dynamic-captions/dcproj_.../srt-...srt"
  }
}

Responses

StatusDescription
200Request succeeded
400Invalid request body or unsupported parameter
401Missing, invalid, or revoked API key
429Rate limit exceeded
500Unexpected processing error
POST/api/v1/dynamic-captions/jobs

Start a Viral Captions render

Starts rendering after the uploaded video is available.

Bearer auth

Parameters

FieldTypeRequiredDetails
projectIdstringYes
Project ID returned by the upload endpoint
body
languagestringNo
Transcription language code
bodydefault: autoSupported ASR languages
templateIdstringNo
Viral caption template ID
placementtop | middle | bottomNo
Caption placement
bodydefault: bottomCaption options
faceTrackbooleanNo
Enable face tracking crop where supported
bodydefault: falseCaption options
aspectRatio9:16 | 16:9 | 1:1No
Output aspect ratio
bodydefault: 9:16Caption options

Examples

Request

{
  "projectId": "dcproj_...",
  "language": "en",
  "templateId": "bold-clean",
  "placement": "bottom",
  "faceTrack": false,
  "aspectRatio": "9:16"
}

Response

{
  "projectId": "dcproj_...",
  "status": "queued",
  "runId": "run_...",
  "estimatedCredits": 9,
  "statusUrl": "/api/v1/.../jobs/dcproj_...",
  "downloadUrl": "/api/v1/.../jobs/dcproj_.../download"
}

Responses

StatusDescription
200Request succeeded
400Invalid request body or unsupported parameter
401Missing, invalid, or revoked API key
429Rate limit exceeded
500Unexpected processing error
GET/api/v1/dynamic-captions/jobs/{projectId}

Get Viral Captions job status

Returns render progress and output metadata.

Bearer auth

Parameters

FieldTypeRequiredDetails
projectIdstringYes
Viral Captions project ID
path

Examples

Response

{
  "projectId": "dcproj_...",
  "status": "queued | processing | completed | failed",
  "progress": 100,
  "outputReady": true,
  "creditsUsed": 9,
  "errorMessage": null,
  "updatedAt": "2026-06-19T14:20:00.000Z"
}

Responses

StatusDescription
200Request succeeded
400Invalid request body or unsupported parameter
401Missing, invalid, or revoked API key
429Rate limit exceeded
500Unexpected processing error
GET/api/v1/dynamic-captions/jobs/{projectId}/download

Create Viral Captions download URL

Returns a signed URL for the rendered MP4 when the job is complete.

Bearer auth

Parameters

FieldTypeRequiredDetails
projectIdstringYes
Viral Captions project ID
path

Examples

Response

{
  "projectId": "dcproj_...",
  "downloadUrl": "https://signed-download-url...",
  "expiresAt": "2026-06-19T15:00:00.000Z",
  "expiresIn": 3600,
  "contentType": "video/mp4",
  "fileSize": 18345678
}

Responses

StatusDescription
200Request succeeded
400Invalid request body or unsupported parameter
401Missing, invalid, or revoked API key
429Rate limit exceeded
500Unexpected processing error

1. Create an upload request

Send video metadata. Add srt only when you want to provide your own captions.

curl -X POST https://www.subclip.app/api/v1/dynamic-captions/uploads \
  -H "Authorization: Bearer $SUBCLIP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "projectName": "captioned-launch-video",
    "video": {
      "fileName": "launch.mp4",
      "contentType": "video/mp4",
      "fileSize": 52428800,
      "durationSeconds": 42,
      "width": 1080,
      "height": 1920
    },
    "srt": {
      "fileName": "launch.srt",
      "contentType": "text/plain",
      "fileSize": 18200
    }
  }'
{
  "projectId": "dcproj_...",
  "uploadExpiresIn": 900,
  "video": {
    "uploadUrl": "https://...",
    "objectKey": "user/dynamic-captions/dcproj_.../video-...",
    "contentType": "video/mp4",
    "expiresIn": 900
  },
  "srt": {
    "uploadUrl": "https://...",
    "objectKey": "user/dynamic-captions/dcproj_.../srt-...",
    "expiresIn": 900
  }
}

2. Upload the video and optional SRT

Upload each file to its returned signed URL. Content-Length must match the actual file size. cURL usually sets it automatically, but Node streams need it explicitly.

curl -X PUT "$VIDEO_UPLOAD_URL" \
  -H "Content-Type: video/mp4" \
  -H "Content-Length: 52428800" \
  --data-binary "@launch.mp4"

curl -X PUT "$SRT_UPLOAD_URL" \
  -H "Content-Type: text/plain" \
  -H "Content-Length: 18200" \
  --data-binary "@launch.srt"
// Node streamed uploads need Content-Length and duplex.
await fetch(upload.video.uploadUrl, {
  method: "PUT",
  headers: {
    "Content-Type": "video/mp4",
    "Content-Length": String(fileStats.size),
  },
  body: createReadStream("./launch.mp4"),
  duplex: "half",
});

3. Start the caption render

Choose language, template, placement, and face tracking. Credits are checked before starting and deducted only after successful render.

curl -X POST https://www.subclip.app/api/v1/dynamic-captions/jobs \
  -H "Authorization: Bearer $SUBCLIP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "projectId": "dcproj_...",
    "language": "en",
    "templateId": "bold-clean",
    "aspectRatio": "9:16",
    "placement": "bottom",
    "faceTrack": true,
    "outputFileName": "launch-captions.mp4"
  }'

4. Poll status

Poll every 5 seconds for normal videos. For longer videos, poll every 15 seconds. Do not poll in a tight loop; if you receive 429 rate_limited, wait until X-RateLimit-Reset before trying again. The output is ready when outputReady is true.

curl https://www.subclip.app/api/v1/dynamic-captions/jobs/dcproj_... \
  -H "Authorization: Bearer $SUBCLIP_API_KEY"

5. Download the result

The Subclip endpoint returns JSON with a short-lived signed download URL. Download that URL to get the MP4 bytes.

DOWNLOAD_JSON=$(curl -s https://www.subclip.app/api/v1/dynamic-captions/jobs/dcproj_.../download \
  -H "Authorization: Bearer $SUBCLIP_API_KEY")

DOWNLOAD_URL=$(echo "$DOWNLOAD_JSON" | jq -r '.downloadUrl')

curl -L "$DOWNLOAD_URL" -o captioned.mp4

Options

FieldRequiredWhat it does
projectIdYesThe ID returned by the upload request.
languageNoASR language, for example en, hi, es, or auto.
templateIdNoViral caption template ID. Defaults to bold-clean.
aspectRatioNoFinal video canvas: 9:16, 16:9, or 1:1. Default is 9:16.
placementNotop, middle, or bottom. Default is bottom.
faceTrackNoWhen true, Subclip analyzes face position, shifts captions away from the face, and keeps the face inside the cropped canvas when possible.
outputFileNameNoFinal MP4 filename returned by the download endpoint.
Framing: if aspectRatio changes the canvas shape, Subclip uses the editor's default cover/crop behavior. If faceTrack is enabled and a face is detected, the crop is nudged to keep that face visible. If no face is found, the normal centered crop is used.

Supported ASR languages

Use language only when no SRT is uploaded. auto lets Subclip detect the spoken language.

CodeLanguage
autoAuto-detect
afAfrikaans
sqAlbanian
amAmharic
arArabic
hyArmenian
asAssamese
azAzerbaijani
baBashkir
euBasque
beBelarusian
bnBengali
bsBosnian
brBreton
bgBulgarian
caCatalan
zhChinese
hrCroatian
csCzech
daDanish
nlDutch
enEnglish
etEstonian
foFaroese
fiFinnish
frFrench
glGalician
kaGeorgian
deGerman
elGreek
guGujarati
htHaitian Creole
haHausa
hawHawaiian
heHebrew
hiHindi
huHungarian
isIcelandic
idIndonesian
itItalian
jaJapanese
jwJavanese
knKannada
kkKazakh
kmKhmer
koKorean
loLao
laLatin
lvLatvian
lnLingala
ltLithuanian
lbLuxembourgish
mkMacedonian
mgMalagasy
msMalay
mlMalayalam
mtMaltese
miMaori
mrMarathi
mnMongolian
myMyanmar
neNepali
noNorwegian
nnNynorsk
ocOccitan
psPashto
faPersian
plPolish
ptPortuguese
paPunjabi
roRomanian
ruRussian
saSanskrit
srSerbian
snShona
sdSindhi
siSinhala
skSlovak
slSlovenian
soSomali
esSpanish
suSundanese
swSwahili
svSwedish
tlTagalog
tgTajik
taTamil
ttTatar
teTelugu
thThai
boTibetan
trTurkish
tkTurkmen
ukUkrainian
urUrdu
uzUzbek
viVietnamese
cyWelsh
yiYiddish
yoYoruba

Template IDs

Pass one of these values in templateId.

#PreviewtemplateIdNameBest for
1
bold-cleanBold CleanLarge clean words with punchy emphasis.
2
ivory-spotlightSpotlightElegant serif captions with strong focus words.
3
serif-storytellerStorytellerEditorial serif captions for narrative videos.
4
authorityAuthorityCompact premium captions for expert-style videos.
5
compositeCompositeLarge bold captions that invert the video beneath them.
6
minimalistMinimalistTight, simple captions with restrained motion.
7
minimalist-whiteMinimalist WhiteClean white captions for simple edits.
8
kineticKineticFast animated captions for energetic clips.
9
kinetic-yellowCinematicKinetic captions with yellow emphasis.
10
composite-one-wordComposite One WordLarge bold one-word captions with Difference compositing.
11
one-wordOne WordOne word at a time for strong hook moments.
12
justifiedJustifiedWider readable lines for dense explanations.

Errors

400 invalid_request: unsupported field, wrong template, bad filename, or malformed JSON.

401 invalid_api_key: missing, invalid, revoked, or missing dynamic_captions permission. Regenerate the key if it was created before Viral Captions access existed.

402 not_enough_credits: the user does not have enough AI credits.

409 output_not_ready: poll status before downloading.

507 storage_quota_exceeded: not enough storage for the uploaded video/SRT.

Inputs and outputs are scheduled for deletion after completion so storage quota is freed. Get your key from Developer Portal.