---
title: "Plan a kinetic-typography edit (CapCut style)"
method: POST
path: "/v1/studio/kinetic"
tags: ["Edit"]
---

# Plan a kinetic-typography edit (CapCut style)

`POST /v1/studio/kinetic`

## Request

- Base URL: `https://apihub.co.il`
- URL: `https://apihub.co.il/v1/studio/kinetic`
- Auth: HTTP bearer

Turns the word timings of a talking-head video into ONE ready body for POST /v1/studio/edit in the CapCut short-form look: no subtitle line — every spoken word lands on the frame it is said, in small cards of 1–3 words (small connector words, one big key word in a rotating display font, acid lime on every other card), a big hook, a punch-zoom rhythm, black title cards with a white flash, emoji stickers, a reused sound kit and a music bed, 9:16 720p. Every element is anchored to a word of the video's transcript (`at` / `during` on the words' ids): the render cuts the pauses from the sound and lands each element on its word's exact frame. Nothing is rendered or generated here — it answers at once, with the numbered words (with ids), the plan's timeline and warnings. Recipe: /skills/full-kinetic.md

**Billing:** Read request — the plan is free; the render is POST /v1/studio/edit · **Rate limit:** 60/min

## Headers

- `Idempotency-Key` string
- `X-Tag` string

## Request body

- object
  - `cut` union: The silence cut; false keeps every pause
    - false
    - object
      - `from` 'audio' | 'words': audio = the render finds the pauses in the sound and cuts them (`remove_silence` with these numbers); every element rides along on its words. words = the plan cuts from the word timings and sends `keep` spans (only for transcripts with real gaps between words — Hebrew timings run into each other)
      - `padding_ms` number
      - `min_pause_ms` number
  - `face` object: Where the face is in the 9:16 frame: x = its centre (0…1), top/bottom = % of the height. The words stay off it; zooms centre on it
    - `x` number
    - `top` number
    - `bottom` number
  - `hook` boolean: The first phrase as a big title in the top band
  - `keep` object[]: `cut.from: "words"` only: seconds of the source the cut must keep — speech the transcript missed
    - `end` number, required
    - `start` number, required
  - `seed` integer: Another seed = another rotation of fonts, positions and effects
  - `music` object: The music bed (never ducked)
    - `url` string, uri, required
    - `volume` number: Omit: levelled ≈ 10 dB under the voice (measured from `cut_audio_url` / `voice_lufs`; 0.3 when unknown)
  - `speed` number: Play faster (1.1 = +10 %). The references talk ≈ 3.5–4.5 words/s; a slower speaker (< 2.8) reads tighter at 1.1
  - `words` object[]: Or the video's timed words yourself (ms, the video's clock)
    - `id` string: Stable id (w0001…); given in order when missing
    - `end` number, required: ms
    - `text` string, required
    - `start` number, required: ms
    - `spoken` string
    - `speaker` string, nullable
  - `accent` string
  - `scenes` object[]: A black typography card (1.2–2.5 s, the speaker hidden, the voice goes on) on the phrase with this word — the thesis
    - `word` integer, required
  - `sounds` object: The sound kit — each file is reused for every moment of its kind
    - `pop` string, uri
    - `riser` string, uri
    - `glitch` string, uri
    - `whoosh` string, uri
  - `source` object: The video's length and frame rate. The endpoint fills it (a probe of the video)
    - `fps` number, required
    - `duration` number, required: seconds
  - `emphasis` integer[]: Indices of the key words (one per phrase gets the big display type). Omit to pick the longest word of each phrase
  - `stickers` object[]: Emoji stickers next to the words they illustrate
    - `url` string, uri, required: A PNG with transparency — e.g. POST /v1/stock/icon with an emoji icon
    - `size` number: % of the width (default 22)
    - `word` integer, required
  - `video_url` string, uri, required: The source video (a public link or an upload's url)
  - `resolution` '720' | '1080': 720 = the references' 720×1280 and 25 % cheaper
  - `voice_lufs` number: The voice's integrated loudness, if you know it (the endpoint measures `cut_audio_url`)
  - `corrections` object[]: Fix a misheard word: its index in the words list and the right text ("" removes a word that was not said — one word heard as two)
    - `text` string, required
    - `word` integer, required
  - `cut_audio_url` string, uri: A WAV of the voice, to set the music level by (POST /v1/studio/convert with `output.format: "wav"`, or the sound-only pass of POST /v1/studio/remove-silence): the voice's loudness is measured there so the music sits ≈ 10 dB under it. Omit: 0.3
  - `transcript_id` string: The transcript of the video itself (POST /v1/speech/transcripts on its url): every element of the plan is anchored to its words, and the render cuts the pauses around them

## Response `200`

Completed

- object
  - `id` string: Execution id — stable across internal retries; use it with GET /v1/executions/{id}
  - `status` 'pending' | 'processing' | 'completed' | 'partial' | 'failed' | 'cancelled' | 'timeout'
  - `operation` string
  - `tag` string, nullable: Your X-Tag, if sent
  - `created_at` string, date-time
  - `completed_at` string, date-time, nullable
  - `output` object: Operation result (see each operation). While a Studio render is processing: `stage` (queued · transcribing · downloading · preparing · cleaning_voice · mixing_audio · rendering · finishing), `phase` (the engine's: download · prepare · voice · audio · encode · qa · upload, or null), `progress` (a percent, 0–100) and `progress_fraction` (0–1), `eta_seconds` (seconds left, never below 0) and `estimate_seconds`
  - `error` string, nullable
  - `usage` object
    - `credits_charged` number, nullable
    - `credits_reserved` number
    - `estimated_credits` number
    - `cost_source` 'provider_reported' | 'calculated' | 'estimated' | 'null', nullable
    - `provider_usage` object, nullable: Normalised consumption, e.g. { VIDEO_SECOND: 22.4 }
  - `balance` object
    - `available` number
    - `reserved` number

## Other responses

- `400`: Invalid input
- `402`: Insufficient credits / project budget
- `404`: Resource not found (or not yours)
- `429`: Rate limited
- `503`: Service temporarily paused

---

[API](https://skmtc.dev/apihub/apis/apihub-one-api-for-chat-image-video-ai.md) · [All operations](https://skmtc.dev/apihub/apis/apihub-one-api-for-chat-image-video-ai/llms.txt) · [OpenAPI document](https://skmtc.dev/apihub/apis/apihub-one-api-for-chat-image-video-ai/revisions/a8caa42835ce?raw)
