Public reference for integrators. Signed-in editors: same content in Dashboard → Help → API & automation, plus Account shortcuts.
Programmatic caption QA for Free+ and Pro accounts. Pro: up to 9,999 successful HTTP 200 v1 calls per UTC day. Create keys under Dashboard → Account → API keys. Failed attempts do not decrement remainingApiRunsToday.
Examples (curl, Node, Python) and a GitHub Action for CI live in the repo examples/ folder.
Machine-readable contract and importable collections for CI pipelines and API clients.
apiKey to your cp_live_… secret.examples/api/ (GitHub).Import in Postman: Import → Link paste the collection URL, then import the environment and select it before sending requests.
Send your secret on every request (TLS required in production). Never put keys in query strings, logs, or browser bundles.
Authorization: Bearer cp_live_...
Key management uses your logged-in session at Account (cookies). Integrations use Bearer only.
https://www.captionpass.com/api/v1/...
| Tier | Daily successful v1 runs (UTC) | Notes |
|---|---|---|
| Anonymous homepage | 5 | Separate cap — not the v1 API. |
| Free+ | 10 | Combined homepage + v1 pool. |
| Pro | Up to 9,999 | Unlimited homepage tool; v1 metered. |
429 rate_limited.Retry-After header — back off exponentially.Legacy keys default to process:write only. Management routes need explicit scopes and matching entitlements. 403 may include details.missingScope or details.missingFeature.
| Scope | Routes |
|---|---|
process:write | POST /api/v1/process |
process:write (ExplainAI) | POST /api/v1/explain — requires Pro workspace + explain entitlement |
account:read | GET /api/v1/me |
usage:read | GET /api/v1/usage |
keys:read / keys:write | GET, POST, DELETE /api/v1/api-keys |
webhooks:read / webhooks:write | GET, PUT /api/v1/webhook (Pro) |
exports:read / exports:write | GET /api/v1/projects, POST /api/v1/projects/{id}/diff (caption_drift add-on), GET/POST/PUT/DELETE /api/v1/export-templates, POST …/validate, POST …/{id}/test (Pro CPES) |
exports:read / exports:write (video) | POST /api/v1/media/upload, POST …/complete, POST /api/v1/jobs/extract (caption_extract), POST /api/v1/jobs/render (caption_render), GET/DELETE /api/v1/jobs/{jobId}, GET /api/v1/artifacts/{artifactId} |
POST only. Multipart multipart/form-data.
file — required (SRT, VTT, SBV, ASS, TTML, or JSON IR).preset — optional, default youtube.fixProfile — optional: warn-only, layout-preserve-breaks, auto-split-sentences, auto-split-cps.Content-Length over ~4.25 MiB → 400 payload_too_large before read.| preset | Output | Intent |
|---|---|---|
youtube | srt | YouTubeSRT for YouTube upload: plain UTF-8 cues, styling stripped per YouTube Help (no vendor line-length cap enforced). |
tiktok | srt | TikTok / ShortsSRT for TikTok/Shorts: vendor format rules only; readability targets are optional suggestions after export. |
html5 | vtt | HTML5 / WebVTT playerWebVTT per W3C: required structure and tag handling; no spec-mandated line length or CPS on export. |
generic | srt | Generic safeCaptionPass safe defaults when the destination is unknown: SRT, plain text, line length and CPS enforced. |
lms | ttml | LMS / TTML (IMSC1-friendly)TTML / IMSC1-friendly output: format and tag rules per spec; line length/CPS available as suggestions. |
instagram-reels | srt | Instagram / ReelsSRT for Meta Reels/Stories: vendor upload rules only; short-line targets are suggestions. |
linkedin | srt | LinkedInSRT for LinkedIn video posts per Help; professional line/CPS targets are suggestions. |
vimeo | vtt | VimeoWebVTT for Vimeo: player-oriented tag rules; line length/CPS are suggestions. |
facebook | srt | Facebook / Meta videoSRT sidecar for Meta video uploads; feed readability targets are suggestions. |
zoom | vtt | Zoom / webinar VTTWebVTT for Zoom/webinar players: format rules only; webinar line/CPS targets are suggestions. |
developer-json | json | Developer JSON (IR)Stable JSON timeline (CaptionPass IR v1) for round-tripping, automation, and future API use. |
curl -sS -X POST "https://www.captionpass.com/api/v1/process" \ -H "Authorization: Bearer $CAPTIONPASS_API_KEY" \ -F "file=@./captions.srt" \ -F "preset=youtube"
JSON: report, output, optional dual-delivery fields (aidedOutput, suggestions, …), and remainingApiRunsToday.
Scope account:read. Returns account profile: userKey, tier, features[], quotas, email.
curl -sS "https://www.captionpass.com/api/v1/me" \ -H "Authorization: Bearer $CAPTIONPASS_API_KEY"
Scope usage:read. Daily cap, today's count, remainingToday, and masked API key list.
curl -sS "https://www.captionpass.com/api/v1/usage" \ -H "Authorization: Bearer $CAPTIONPASS_API_KEY"
GET /api/v1/api-keys — keys:read; masked prefixes only.POST /api/v1/api-keys — keys:write; body { "name", "scopes": ["process:write", ...] }; returns one-time secret.DELETE /api/v1/api-keys/{keyId} — revoke.Scopes webhooks:read / webhooks:write. Requires PRO_WORKSPACE.
GET /api/v1/webhook — config + masked secret.PUT /api/v1/webhook — HTTPS URL required; optional rotateSecret.Dashboard export-complete webhooks (HMAC X-CaptionPass-Signature) are documented below — same secret concept as Account → Export webhooks.
Pro ADVANCED_EXPORTS. JavaScript must define exportTimeline(cues, ctx). See Custom exports (CPES) for the full language reference.
| Action | Route | Notes |
|---|---|---|
| List | GET /api/v1/export-templates | All saved templates. |
| Get | GET /api/v1/export-templates/{id} | 404 if not yours. |
| Create | POST /api/v1/export-templates | Validates script before save. |
| Update | PUT /api/v1/export-templates/{id} | Optional revision for optimistic lock. |
| Delete | DELETE /api/v1/export-templates/{id} | |
| List projects | GET /api/v1/projects | Ready/empty projects for choosing test projectId. |
| Validate / test / both | POST /api/v1/export-templates/validate | Body: scriptSource, mode, projectId (test/both). |
| Test saved template | POST /api/v1/export-templates/{id}/test | Body: projectId, optional mode (default test). |
remainingApiRunsToday (same daily pool as POST /api/v1/process).Project ID for test
Test mode requires a ready project UUID. Sign in and use Library → Custom exports to see project IDs, or open a project and copy the ID from the URL path.
curl -sS -X POST "https://www.captionpass.com/api/v1/export-templates/validate" \
-H "Authorization: Bearer $CAPTIONPASS_API_KEY" \
-H "Content-Type: application/json" \
-d '{"scriptSource":"function exportTimeline(cues,ctx){ ... }","mode":"both","projectId":"YOUR-PROJECT-UUID"}'{ "error": { "code": "unauthorized", "message": "…", "details": { } } }| HTTP | error.code | When |
|---|---|---|
| 401 | unauthorized | Missing/invalid Bearer, unknown or revoked key. |
| 403 | forbidden | Missing scope, missing entitlement (e.g. Pro workspace), or V1_API disabled. |
| 429 | rate_limited | Per-key burst or export-operation burst exceeded. |
| 429 | quota_exceeded | Daily successful v1 cap exhausted (UTC day). |
| 400 | bad_request | Invalid JSON, bad preset, invalid script, missing fields. |
| 400 | payload_too_large | Declared Content-Length or file too large. |
| 413 | payload_too_large | Engine refused input size. |
| 422 | processing_failed | Parse/rule failure on process or export test. |
| 501 | not_implemented | Route not enabled on this deployment (e.g. v1 project test). |
| 503 | unavailable | Backing store or WASM runtime not configured. |
| code | Meaning |
|---|---|
empty_input | Parser: file was empty. |
no_cues | Parser: no valid cues found. |
invalid_timestamp | Parser: malformed time range. |
missing_webvtt_header | VTT: WEBVTT missing on line 1. |
overlapping_cues | Rule: two cues overlap in time. |
reading_speed_high | Rule: CPS above preset maximum for a cue. |
too_many_lines | Rule: cue exceeds max lines per cue. |
strip_styling | Rule: markup removed per preset. |
The homepage converter uses POST /api/process with browser guards — not for integrations. Use POST /api/v1/process with Bearer keys.
Configure under Account → Export webhooks. On each successful export, CaptionPass POSTs JSON with X-CaptionPass-Signature (HMAC-SHA256). Event export_complete includes projectId and artifact list.
{
"event": "export_complete",
"receipt": {
"version": 1,
"kind": "single_export",
"projectId": "…",
"irRevision": 3,
"artifacts": [{ "preset": "youtube", "exportId": "…", "filename": "…" }]
}
}Illustrative JSON bodies. Field sets may include additional keys on success; treat unknown fields as optional.
{
"report": { "diagnostics": [], "summary": "…" },
"output": "1\n00:00:01,000 --> 00:00:04,000\n…",
"aidedOutput": "1\n00:00:01,000 --> 00:00:04,000\n…",
"aidedSameAsDelivery": false,
"suggestions": [{ "code": "reading_speed_high", "cueIndex": 2 }],
"deliveryStatus": "will_adapt",
"aidedStatus": "ready",
"remainingApiRunsToday": 19
}{
"userKey": "usr_…",
"tier": "free_plus",
"email": "you@example.com",
"features": ["API_V1", "API_KEYS"],
"quotas": { "v1DailySuccessCap": 10, "remainingToday": 7 }
}{
"cap": 10,
"usedToday": 3,
"remainingToday": 7,
"keys": [{ "keyId": "…", "prefix": "cp_live_abcd", "name": "CI" }]
}{
"error": {
"code": "unauthorized",
"message": "Missing or invalid API key."
}
}{
"error": {
"code": "forbidden",
"message": "Missing scope.",
"details": { "missingScope": "account:read" }
}
}{
"error": {
"code": "quota_exceeded",
"message": "Daily API conversion limit reached. Try again tomorrow."
}
}When Account → Export webhooks is configured, CaptionPass POSTs to your HTTPS endpoint on each successful export. Verify X-CaptionPass-Signature before trusting the body.
{
"event": "export_complete",
"receipt": {
"version": 1,
"kind": "single_export",
"projectId": "a0000000-0000-4000-8000-000000000001",
"irRevision": 3,
"artifacts": [
{ "preset": "youtube", "exportId": "delivery", "filename": "youtube-delivery.srt" }
]
}
}import { createHmac, timingSafeEqual } from "node:crypto";
export function verifyCaptionPassWebhook(rawBody, signatureHeader, secret) {
const expected = createHmac("sha256", secret).update(rawBody).digest("hex");
const got = String(signatureHeader || "").replace(/^sha256=/i, "");
if (got.length !== expected.length) return false;
return timingSafeEqual(Buffer.from(got, "utf8"), Buffer.from(expected, "utf8"));
}2xx quickly; retries are best-effort. Use receipt.irRevision for idempotency.Paths are versioned (/api/v1/…). Breaking changes will ship under /api/v2 when needed. Non-breaking additions (new optional JSON fields, new presets) may appear without a version bump — clients should ignore unknown fields.
Retry-After header; use exponential backoff on 429.200 responses decrement remainingApiRunsToday (UTC day).Base URL for examples: https://www.captionpass.com