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.standard — optional accessibility standard to grade against. Adds a report.standard verdict, clause by clause. An unrecognised value is rejected rather than ignored.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"
A preset says which platform the file is for. A standard says which regulation it is being graded against — and they are independent, so a delivery can name both.
| standard | Document | Who it binds |
|---|---|---|
wcag-2.1-aa | WCAG 2.1 Level AAW3C Web Content Accessibility Guidelines 2.1, Level AA (W3C Recommendation, 5 June 2018) | The technical standard named by the ADA Title II web rule for state and local government content, due 26 April 2027 for large entities and 26 April 2028 for small ones. |
en-301-549 | EN 301 549 (European accessibility)ETSI EN 301 549 V3.2.1 (2021-03), Accessibility requirements for ICT products and services | The harmonised European standard behind the European Accessibility Act, in force since 28 June 2025, and behind EU public-sector procurement. |
fcc-79.1 | FCC caption quality (47 CFR 79.1)47 CFR 79.1(j)(2) — caption quality standards, adopted by FCC 14-12 (2014) | Video programming distributed on US television, and — through 47 CFR 79.4 — clips of that programming redistributed online. |
dcmp | DCMP Captioning Key (educational media)Described and Captioned Media Program, Captioning Key: Guidelines and Preferred Techniques | Educational media, and the house style most US school and university media libraries are procured against. |
report.standard.clauses[] gives each clause a status of pass, fail, or not_evaluated, with the findings that decided it and, where the engine cannot settle a clause from a caption file alone, the reason. Accuracy under FCC 79.1 needs the audio, so it is always reported as not evaluated — never as a pass.
curl -sS -X POST "https://www.captionpass.com/api/v1/process" -H "Authorization: Bearer $CAPTIONPASS_API_KEY" -F "file=@./captions.srt" -F "preset=youtube" -F "standard=wcag-2.1-aa"
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 Bearer token, or a key nobody has heard of. |
| 401 | api_key_revoked | The key was deliberately revoked. Create a new one. |
| 401 | api_key_expired | The key reached its expiresAt. Renew it from the account page — renewal does not change the secret, so nothing needs redeploying. |
| 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. |
| 404 | not_found | No route matches that method and path, or the named resource does not exist. |
| 501 | not_implemented | Route not enabled on this deployment (e.g. v1 project test). |
| 500 | internal_error | Unhandled server failure. The message is deliberately generic; the detail is in our logs, not in your response. |
| 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