> ## Documentation Index
> Fetch the complete documentation index at: https://docs.captioncraft.studio/llms.txt
> Use this file to discover all available pages before exploring further.

# Create subtitles

> Create a captioned video with automatic duration inspection.

Requires `subtitles:write`. Submit a direct HTTPS video URL and poll the returned `status_url` every five seconds. Each accepted submission creates a new job, even with identical input.

Choose any of the 16 presets and optionally override typography, layout, background, outline, shadow, and applicable highlight colors through `style`. Omitted fields inherit the preset, including fields within nested objects. [Caption styles](/caption-styles) explains all controls and preset-specific behavior.

<Note>Creating a job requires a positive prepaid balance. After inspecting the video, the API reserves its actual duration rounded up before transcription. If credit is insufficient, the job fails with `INSUFFICIENT_CREDITS`. Successful jobs consume the reservation; failed and canceled jobs release it. Videos can be up to 600 seconds long.</Note>

See [Quickstart](/quickstart) for a full submission and download example, and [Media requirements](/media-requirements) for accepted sources.


## OpenAPI

````yaml openapi.json POST /v1/subtitles
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://api.captioncraft.studio
security: []
paths:
  /v1/subtitles:
    post:
      summary: Create a captioned video
      description: >-
        Each accepted submission creates a new job, including repeated input.
        Supply optional srt file contents to skip ElevenLabs transcription;
        audio is then optional and language is ignored. SRT cue boundaries are
        preserved, with word timings estimated evenly within each cue and layout
        adapted to the preset. Requires a positive prepaid balance. After
        inspecting the video, reserves ceil(actual duration) before caption
        preparation. 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. JSON request limit:
        512 KiB; SRT limit: 256 KiB UTF-8 and 8192 words.
      operationId: createSubtitles
      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
              example:
                id: example_job_id
                status: ingesting
                status_url: https://api.captioncraft.studio/v1/jobs/example_job_id
          headers:
            Location:
              description: Status URL for the accepted job.
              schema:
                type: string
                format: uri
            Retry-After:
              description: Recommended polling interval in seconds.
              schema:
                type: integer
                example: 5
        '400':
          description: Invalid request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Missing or invalid API key
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '402':
          description: Insufficient prepaid seconds
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Missing key scope or disabled account
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '413':
          description: JSON body exceeds 512 KiB
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '415':
          description: 'Use Content-Type: application/json'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: Rate or concurrency limit exceeded; honor Retry-After
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          headers:
            Retry-After:
              description: Minimum retry delay in seconds.
              schema:
                type: integer
                example: 5
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '503':
          description: Processing is not configured
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - apiKey: []
components:
  schemas:
    SubtitleRequest:
      type: object
      properties:
        video_url:
          type: string
          maxLength: 4096
          format: uri
          description: >-
            Direct HTTPS MP4, MOV, or WebM URL. No redirects or extra auth
            headers. Maximum 500 MiB; must remain valid until downloaded.
          examples:
            - https://your-cdn.example/video.mp4
        preset:
          default: classic
          type: string
          enum:
            - classic
            - highlight
            - smash
            - box
            - push
            - elegant
            - ogre
            - outline
            - paper-ink
            - action
            - prompter
            - storytelling
            - karaoke
            - glow
            - thin&bold
            - background
          description: Caption preset. Omitted style properties use this preset's defaults.
        language:
          type: string
          pattern: ^[a-z]{2,3}$
          description: >-
            Optional lowercase two- or three-letter language code supported by
            transcription. Omit for automatic language detection. Does not
            translate. Ignored when srt is provided.
          examples:
            - en
        srt:
          type: string
          maxLength: 262144
          description: >-
            Optional SRT file contents (not a URL), up to 256 KiB UTF-8 and 8192
            words. Skips transcription; language is ignored. Word timings are
            estimated evenly within each cue. Cue times must fit within the
            video. The original SRT is returned unchanged.
          examples:
            - |
              1
              00:00:00,000 --> 00:00:02,000
              Hello world!
        style:
          default: {}
          type: object
          properties:
            position:
              description: >-
                Vertical caption placement; omitted values use the preset's
                default.
              type: string
              enum:
                - top
                - center
                - bottom
            text_color:
              description: Text color as a six-digit hexadecimal 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
          description: >-
            Optional caption style overrides. Omitted fields (including nested
            fields) inherit the selected preset. Font size is derived from
            font_family and text_width; horizontal caption placement follows the
            preset. Direct font_size and horizontal_position overrides are not
            accepted. GET /v1/presets lists defaults, supported controls and
            preset-specific behavior.
      required:
        - video_url
      additionalProperties: false
      examples:
        - video_url: https://your-cdn.example/video.mp4
          preset: highlight
          style:
            highlight_color: '#7651E8'
    Error:
      type: object
      required:
        - error
      properties:
        error:
          type: object
          properties:
            code:
              type: string
            message:
              type: string
            request_id:
              type: string
          required:
            - code
            - message
            - request_id
  securitySchemes:
    apiKey:
      type: http
      scheme: bearer
      bearerFormat: cc_ API key

````