{"openapi":"3.1.0","info":{"title":"CaptionCraft API","version":"1.0.0","description":"Create captioned MP4 videos from a video URL. Jobs are asynchronous. Poll every 5 seconds. Media is retained for 24 hours; request a fresh job response to retrieve result URLs. All word timestamps use seconds."},"servers":[{"url":"https://sincere-boar-34.convex.site"}],"components":{"securitySchemes":{"apiKey":{"type":"http","scheme":"bearer","bearerFormat":"cc_ API key"}},"schemas":{"SubtitleRequest":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"video_url":{"type":"string","maxLength":4096,"format":"uri"},"preset":{"default":"classic","type":"string","enum":["classic","highlight","smash","box","push","elegant","ogre","outline","paper-ink","action","prompter","storytelling","karaoke","glow","thin&bold","background"]},"language":{"type":"string","pattern":"^[a-z]{2,3}$"},"style":{"default":{},"type":"object","properties":{"position":{"description":"Vertical caption placement.","type":"string","enum":["top","center","bottom"]},"text_color":{"description":"Text fill as a six-digit hex color.","type":"string","pattern":"^#[0-9a-fA-F]{6}$"},"highlight_color":{"description":"Active-word color for highlight, push, action and karaoke; active-word box color for box. Ignored by other presets for compatibility.","type":"string","pattern":"^#[0-9a-fA-F]{6}$"},"font_family":{"description":"A bundled font; custom font URLs are not accepted.","type":"string","enum":["Inter","Urbanist","Rubik","Bangers","Paytone One","Slackey","Permanent Marker","Caveat Brush","Zilla Slab","Young Serif","Instrument Serif","Bebas Neue","Coiny"]},"font_weight":{"description":"Regular (400) or bold (700). thin&bold animates its own weight.","anyOf":[{"type":"number","const":400},{"type":"number","const":700}]},"font_style":{"type":"string","enum":["normal","italic"]},"text_alignment":{"description":"Alignment of lines within the caption block.","type":"string","enum":["left","center","right"]},"text_case":{"description":"Visual casing only; downloaded transcripts preserve the original words.","type":"string","enum":["none","uppercase","lowercase","capitalize"]},"text_width":{"description":"Text density: small uses larger type and fewer words per line. Font size is derived from font_family and text_width. Defaults to the preset's width for portrait/square, large for landscape.","type":"string","enum":["small","medium","large"]},"line_count":{"description":"Maximum lines per cue. 0 displays one word at a time; 100 allows up to 100 lines. Smash defaults to 0.","anyOf":[{"type":"number","const":0},{"type":"number","const":1},{"type":"number","const":2},{"type":"number","const":3},{"type":"number","const":100}]},"scale":{"description":"Caption scale multiplied by video width / 1080. Defaults to the preset's scale for portrait/square, 0.55 for landscape.","type":"number","minimum":0.2,"maximum":1},"offset":{"description":"Pixel offsets in output-video coordinates. Left minus right moves horizontally; top minus bottom vertically. Unspecified top/bottom inherit the preset plus an inset on the selected edge: 20% of height for portrait/square, 14% for landscape. Explicit values replace the resolved offset, including zero.","type":"object","properties":{"left":{"type":"number","minimum":-1920,"maximum":1920},"top":{"type":"number","minimum":-1920,"maximum":1920},"right":{"type":"number","minimum":-1920,"maximum":1920},"bottom":{"type":"number","minimum":-1920,"maximum":1920}},"additionalProperties":false},"background":{"description":"Caption background. Set type to enable it; color and opacity alone preserve the preset's background type.","type":"object","properties":{"type":{"type":"string","enum":["none","line","line-rounded","box","box-rounded"]},"color":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"},"opacity":{"type":"number","minimum":0,"maximum":1}},"additionalProperties":false},"outline":{"description":"Text outline on the caption canvas. Thickness 0 disables it.","type":"object","properties":{"color":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"},"thickness":{"type":"number","minimum":0,"maximum":20}},"additionalProperties":false},"shadow":{"description":"Text shadow. Set enabled to show it. Distance and angle determine its position: 0 degrees points down, 90 points right.","type":"object","properties":{"enabled":{"type":"boolean"},"color":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"},"blur":{"type":"number","minimum":0,"maximum":40},"distance":{"type":"number","minimum":0,"maximum":20},"angle":{"type":"number","minimum":-180,"maximum":180}},"additionalProperties":false}},"additionalProperties":false}},"required":["video_url"],"additionalProperties":false},"SubtitleStyle":{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"position":{"description":"Vertical caption placement.","type":"string","enum":["top","center","bottom"]},"text_color":{"description":"Text fill as a six-digit hex color.","type":"string","pattern":"^#[0-9a-fA-F]{6}$"},"highlight_color":{"description":"Active-word color for highlight, push, action and karaoke; active-word box color for box. Ignored by other presets for compatibility.","type":"string","pattern":"^#[0-9a-fA-F]{6}$"},"font_family":{"description":"A bundled font; custom font URLs are not accepted.","type":"string","enum":["Inter","Urbanist","Rubik","Bangers","Paytone One","Slackey","Permanent Marker","Caveat Brush","Zilla Slab","Young Serif","Instrument Serif","Bebas Neue","Coiny"]},"font_weight":{"description":"Regular (400) or bold (700). thin&bold animates its own weight.","anyOf":[{"type":"number","const":400},{"type":"number","const":700}]},"font_style":{"type":"string","enum":["normal","italic"]},"text_alignment":{"description":"Alignment of lines within the caption block.","type":"string","enum":["left","center","right"]},"text_case":{"description":"Visual casing only; downloaded transcripts preserve the original words.","type":"string","enum":["none","uppercase","lowercase","capitalize"]},"text_width":{"description":"Text density: small uses larger type and fewer words per line. Font size is derived from font_family and text_width. Defaults to the preset's width for portrait/square, large for landscape.","type":"string","enum":["small","medium","large"]},"line_count":{"description":"Maximum lines per cue. 0 displays one word at a time; 100 allows up to 100 lines. Smash defaults to 0.","anyOf":[{"type":"number","const":0},{"type":"number","const":1},{"type":"number","const":2},{"type":"number","const":3},{"type":"number","const":100}]},"scale":{"description":"Caption scale multiplied by video width / 1080. Defaults to the preset's scale for portrait/square, 0.55 for landscape.","type":"number","minimum":0.2,"maximum":1},"offset":{"description":"Pixel offsets in output-video coordinates. Left minus right moves horizontally; top minus bottom vertically. Unspecified top/bottom inherit the preset plus an inset on the selected edge: 20% of height for portrait/square, 14% for landscape. Explicit values replace the resolved offset, including zero.","type":"object","properties":{"left":{"type":"number","minimum":-1920,"maximum":1920},"top":{"type":"number","minimum":-1920,"maximum":1920},"right":{"type":"number","minimum":-1920,"maximum":1920},"bottom":{"type":"number","minimum":-1920,"maximum":1920}},"additionalProperties":false},"background":{"description":"Caption background. Set type to enable it; color and opacity alone preserve the preset's background type.","type":"object","properties":{"type":{"type":"string","enum":["none","line","line-rounded","box","box-rounded"]},"color":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"},"opacity":{"type":"number","minimum":0,"maximum":1}},"additionalProperties":false},"outline":{"description":"Text outline on the caption canvas. Thickness 0 disables it.","type":"object","properties":{"color":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"},"thickness":{"type":"number","minimum":0,"maximum":20}},"additionalProperties":false},"shadow":{"description":"Text shadow. Set enabled to show it. Distance and angle determine its position: 0 degrees points down, 90 points right.","type":"object","properties":{"enabled":{"type":"boolean"},"color":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"},"blur":{"type":"number","minimum":0,"maximum":40},"distance":{"type":"number","minimum":0,"maximum":20},"angle":{"type":"number","minimum":-180,"maximum":180}},"additionalProperties":false}},"additionalProperties":false},"Preset":{"type":"object","required":["id","name","description","animation","defaults","supported_style_fields","style_notes"],"properties":{"id":{"type":"string","enum":["classic","highlight","smash","box","push","elegant","ogre","outline","paper-ink","action","prompter","storytelling","karaoke","glow","thin&bold","background"]},"name":{"type":"string"},"description":{"type":"string"},"animation":{"type":"string","description":"Animation selected by the preset; read-only."},"defaults":{"$ref":"#/components/schemas/SubtitleStyle"},"supported_style_fields":{"type":"array","items":{"type":"string","enum":["position","text_color","highlight_color","font_family","font_weight","font_style","text_alignment","text_case","text_width","line_count","scale","offset","background","outline","shadow"]},"description":"Style fields that affect this preset. Nested groups are partially overridable."},"style_notes":{"type":"object","additionalProperties":{"type":"string"},"description":"Preset-specific behavior keyed by style field path."}}},"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"request_id":{"type":"string"}}}}},"Job":{"type":"object","required":["id","status","progress","usage"],"properties":{"id":{"type":"string"},"status":{"enum":["queued","ingesting","transcribing","rendering","completed","failed","canceled"]},"progress":{"type":"number","minimum":0,"maximum":100},"created_at":{"type":"string","format":"date-time"},"expires_at":{"type":["string","null"],"format":"date-time"},"video":{"type":["object","null"],"properties":{"url":{"type":"string","format":"uri"},"content_type":{"const":"video/mp4"}}},"subtitles":{"type":"object","properties":{"srt_url":{"type":["string","null"]},"transcript_url":{"type":["string","null"]}}},"usage":{"type":"object","properties":{"reserved_seconds":{"type":"integer"},"billed_seconds":{"type":"integer"}}},"error":{"type":["object","null"],"properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}},"paths":{"/v1/presets":{"get":{"operationId":"listPresets","summary":"List available caption styles","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"presets":{"type":"array","items":{"$ref":"#/components/schemas/Preset"}}}}}}}}}},"/v1/subtitles":{"post":{"operationId":"createSubtitles","summary":"Create a captioned video","description":"Each accepted submission creates a new job, including repeated input. Requires a positive prepaid balance. After inspecting the video, reserves ceil(actual duration) before transcription. Insufficient credit at inspection fails the job with INSUFFICIENT_CREDITS. Charges ceil(actual duration) exactly once on success; failures and cancellations release the reservation. Direct HTTPS MP4/MOV/WebM URLs only; redirects are not followed. Maximum 600 seconds, 500 MiB and 1080p in either orientation.","security":[{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubtitleRequest"}}}},"responses":{"202":{"description":"Accepted; poll status_url every five seconds","content":{"application/json":{"schema":{"type":"object","required":["id","status","status_url"],"properties":{"id":{"type":"string"},"status":{"type":"string"},"status_url":{"type":"string","format":"uri"}}}}}},"400":{"description":"Request failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Request failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Request failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Request failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Request failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/jobs/{id}":{"get":{"operationId":"getSubtitleJob","summary":"Get progress and result downloads","security":[{"apiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Job"}}}},"401":{"description":"Request failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Request failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Request failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/jobs/{id}/cancel":{"post":{"operationId":"cancelSubtitleJob","summary":"Cancel an unfinished job and release credits","security":[{"apiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string"}}}}}},"401":{"description":"Request failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Request failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/usage":{"get":{"operationId":"getUsage","summary":"Read prepaid usage in seconds","security":[{"apiKey":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"available_seconds":{"type":"integer","minimum":0},"reserved_seconds":{"type":"integer","minimum":0},"consumed_seconds":{"type":"integer","minimum":0},"active_jobs":{"type":"integer","minimum":0},"concurrency_limit":{"type":"integer","minimum":0}}}}}},"401":{"description":"Request failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Request failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}}}