Skip to content

Automation API

Turn any video into a captioned MP4 with one request. Jobs run on CaptionTik’s render workers with the same engine and templates as the editor. Available on the Pro and Business plans; API render minutes are metered against your plan.

Base URL: https://captiontik.cyou/api/v1

Authentication

Create a key in Dashboard → API & jobs. Send it as a bearer token. Keys are shown once; revoke them at any time.

curl https://captiontik.cyou/api/v1/me \
  -H "Authorization: Bearer csk_live_XXXXXXXX"

Uploads (optional)

If your video is not publicly reachable, request a presigned upload URL, PUT the file to it, then reference the returned uploadKey.

curl -X POST https://captiontik.cyou/api/v1/uploads \
  -H "Authorization: Bearer $CAPTIONTIK_KEY" -H "Content-Type: application/json" \
  -d '{"filename":"talk.mp4","contentType":"video/mp4","size":48211200}'
# → { "uploadKey": "uploads/usr_…/talk.mp4", "uploadUrl": "https://…", "expiresIn": 3600 }

curl -X PUT --upload-file talk.mp4 -H "Content-Type: video/mp4" "<uploadUrl>"

Create a job

POST /jobs

curl -X POST https://captiontik.cyou/api/v1/jobs \
  -H "Authorization: Bearer $CAPTIONTIK_KEY" -H "Content-Type: application/json" \
  -d '{
    "videoUrl": "https://example.com/talk.mp4",
    "template": "juno",
    "variant": 1,
    "controls": { "highlight-color": "#D9A85B" },
    "language": "en",
    "aiStyling": true,
    "autoCutSilences": false,
    "resolution": "1080p",
    "subtitleFormats": ["srt", "vtt"],
    "wordLevel": false,
    "webhookUrl": "https://your.app/hooks/captiontik"
  }'
# → 202 { "id": "cm3…", "status": "queued", … }
FieldTypeDescription
videoUrl / uploadKeystringOne is required. Public http(s) URL or a key from /uploads.
templatestringTemplate id from GET /templates. Default juno.
variantintegerColour preset index of the template.
controlsobjectOverrides for the template’s style controls (ids from GET /templates/:id).
languagestringISO code; omit to auto-detect.
subtitlesstringSRT or WebVTT text to use instead of transcribing.
aiStylingbooleanTag hook, emphasis words, entities and emoji with AI (counts one AI run).
diarizebooleanLabel speakers when the transcription provider supports it; each speaker gets the template’s next colour preset.
autoCutSilencesbooleanRemove pauses longer than 0.6 s.
resolutionsource | 720p | 1080p | 4kClamped to your plan’s maximum.
formatmp4 | webmOutput container. Default mp4.
subtitleFormatsarrayAny of srt, vtt, ass, sbv, txt.
wordLevelbooleanPer-word timing in subtitle files where the format allows.
webhookUrlstringReceives the job JSON when it completes or fails.
metadataobjectYour own string key/values, echoed back.

Job status

GET /jobs/:id — poll every few seconds. GET /jobs lists your recent jobs. DELETE /jobs/:id cancels a queued job.

{
  "id": "cm3…",
  "status": "completed",          // queued | downloading | transcribing | styling | rendering | uploading | completed | failed | cancelled
  "progress": 1,
  "durationSec": 42.3,
  "output": { "url": "https://…/captioned.mp4", "expiresIn": 86400 },
  "subtitles": { "srt": "https://…", "vtt": "https://…" },
  "error": null,
  "createdAt": "2026-10-30T09:12:00.000Z",
  "completedAt": "2026-10-30T09:13:10.000Z"
}

Webhooks

When a job finishes, CaptionTik POSTs the job JSON to your webhookUrl with headers X-CaptionTik-Timestamp and X-CaptionTik-Signature = hex HMAC-SHA256 of `${timestamp}.${rawBody}` using your webhook secret (Dashboard → API). Reject requests older than 5 minutes.

import crypto from 'node:crypto';
function verify(rawBody, ts, sig, secret) {
  const expected = crypto.createHmac('sha256', secret).update(`${ts}.${rawBody}`).digest('hex');
  return Math.abs(Date.now() / 1000 - Number(ts)) < 300 &&
    crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(sig));
}

Templates

GET /templates lists every template (id, name, category, description, colour presets). GET /templates/:id returns its style controls with types, defaults and bounds.

Errors & limits

StatusMeaning
400Invalid request body (details in issues).
401Missing or invalid API key.
402Monthly limit reached for your plan.
403Plan does not include the API, or account suspended.
404Job not found.
429Too many concurrent jobs (Pro 3, Business 10).

Outputs are kept for 7 days. Max input duration: 30 minutes per job.