---
title: "Clip, its video and the edit state for an orientation"
method: GET
path: "/api/clips/{id}"
tags: ["clips"]
---

# Clip, its video and the edit state for an orientation

`GET /api/clips/{id}`

## Request

- Base URL: `https://cliponit.app`
- URL: `https://cliponit.app/api/clips/{id}`
- Auth: one of:
  - HTTP bearer
  - API key in cookie `session`
  - OAuth 2 (authorization code, authorization URL `https://cliponit.app/oauth/authorize`, token URL `https://cliponit.app/oauth/token`, scopes: `clips`)

Creates the default edit for the orientation if missing (layout = orientation, one full-frame keyframe, subtitles = account preset). `updateClipEdit` is a partial patch, so reading first is optional.

## Query parameters

- `orientation` 'vertical' | 'horizontal' | 'square' | 'portrait45': vertical = 9:16 1080x1920 (TikTok/Reels/Shorts), horizontal = 16:9 1920x1080 (YouTube), square = 1:1 1080x1080 (feed), portrait45 = 4:5 1080x1350 (Instagram feed). auto-reframe supports vertical|horizontal only.

## Response `200`

Clip + video + edit

- ClipDetail
  - `clip` ClipBase, required
    - `id` string, uuid, required
    - `video_id` string, uuid, required
    - `position` integer, required: Chronological order
    - `title` string, required
    - `start_s` number, required: Absolute start in the source video (seconds)
    - `end_s` number, required: Absolute end (seconds)
    - `created_at` string, required
  - `video` ClipVideo, required: Source video summary attached to a clip
    - `id` string, uuid
    - `title` string
    - `duration_s` number, nullable
    - `width` integer, nullable
    - `height` integer, nullable
    - `is_demo` integer
    - `language` string, nullable: ISO code detected by the transcription (e.g. `fr`)
    - `url` string
  - `edit` Edit, required: Complete edit state of a clip for one orientation, as returned by `getClip` / `updateClipEdit`.
    - `layout` 'vertical' | 'horizontal' | 'split' | 'trio' | 'spotlight' | 'centered', required: How source zones fill the output frame. `vertical`: 1 zone cropped to 9:16. `horizontal`: full frame (0 zones). `split`: 2 zones stacked (top, bottom). `trio`: 3 zones stacked. `spotlight`: 1 zone over a blurred full-frame background. `centered`: 1 square zone on a blue (#1e3a8a) background.
    - `keyframes` Keyframe[], required
      - `t` number, required
      - `layout` 'vertical' | 'horizontal' | 'split' | 'trio' | 'spotlight' | 'centered', required: How source zones fill the output frame. `vertical`: 1 zone cropped to 9:16. `horizontal`: full frame (0 zones). `split`: 2 zones stacked (top, bottom). `trio`: 3 zones stacked. `spotlight`: 1 zone over a blurred full-frame background. `centered`: 1 square zone on a blue (#1e3a8a) background.
      - `zones` Zone[], required
        - `x` number, required
        - `y` number, required
        - `w` number, required
        - `h` number, required
      - `ease` 'cut' | 'smooth' | '': `cut` = hard switch; `smooth` = zones glide from the previous keyframe over the 0.6 s before `t` (same layout only)
    - `cuts` Cut[], required
      - `start` number, required
      - `end` number, required
    - `subtitles` Subtitles, required: Burned-in subtitles. All fields except the required ones have defaults and are always returned by `getClip`.
      - `enabled` boolean, required
      - `color` 'yellow' | 'white' | 'green' | 'cyan' | 'pink' | 'orange' | 'rainbow', required: Accent colour (current word in karaoke, text otherwise)
      - `case` 'normal' | 'upper' | 'lower', required
      - `lang` string, required: `original` or an ISO 639-1 code (`en`, `es`…) to translate — requires `translate` in the plan
      - `overrides` SubtitleOverride[]
        - `start` number, required
        - `end` number, required
        - `text` string, required
      - `style` 'karaoke' | 'boxed' | 'outline' | 'glow' | 'minimal'
      - `font` 'Inter' | 'Montserrat' | 'Bangers' | 'Poppins' | 'Arial'
      - `position` 'bottom' | 'middle' | 'top'
      - `size` 1 | 2 | 3: 52/64/80 px in 9:16 (×7/8 in 16:9)
      - `words_per_line` integer
      - `animate` boolean: Pop ×1.10 on the current word
      - `hook` Hook: Title card burned at the top of the frame during the first `duration_s` seconds.
        - `enabled` boolean
        - `text` string, nullable: null = the clip title
        - `duration_s` number
        - `style` 'card' | 'plain'
    - `broll` Broll[], required
      - `id` string, required
      - `start` number, required
      - `end` number, required
      - `src` 'pexels' | 'upload', required
      - `path` string, required: Server path under data/broll/ (send back unchanged)
      - `preview_url` string, nullable
      - `query` string, nullable
    - `music` Music, nullable, required: Background music from the user's library (`listMusic`), looped, faded, ducked under the voice.
      - `music_id` string, uuid, required
      - `volume` number
      - `ducking` boolean: Lower the music while someone speaks
      - `fade_s` number: Fade in/out in seconds
    - `emojis` Emoji[], required
      - `start` number, required
      - `end` number, required
      - `emoji` string, required
      - `x` number
      - `y` number: 0.58 = just above the subtitles
      - `size` 1 | 2 | 3: 10/14/18 % of the output width

## Other responses

- `404`: Resource not found or not owned by the user

---

[API](https://skmtc.dev/cliponit/apis/cliponit-api.md) · [All operations](https://skmtc.dev/cliponit/apis/cliponit-api/llms.txt) · [OpenAPI document](https://skmtc.dev/cliponit/apis/cliponit-api/revisions/10e3e4327922?raw)
