---
title: "Create a music video"
method: POST
path: "/music-videos"
tags: ["Music"]
---

# Create a music video

`POST /music-videos`

Builds a music video: your song plus AI visuals, synced captions, and an optional waveform.

**Pick the song (exactly one):**
- `musicId`: a completed song from `POST /music` (see `GET /music`).
- `musicAssetId`: a track you uploaded with `POST /uploads` (purpose `music`).

**Pick the visuals with `visualMode`:**
- `ai-images`: AI generates a new image every few seconds (set `secondsPerImage`).
- `ai-video`: AI generates short video clips across the song.
- `cover-image`: a single still image for the whole song (requires `coverImageAssetId`).

Returns a `videoId` (a video). Poll `GET /videos/{id}` until `status` is `completed`, then export it with `POST /exports` and download with `GET /exports/download`, or publish it.

**Cost:** depends on the visual mode, quality, and song length (see the response `estimatedCredits`). Credits are refunded automatically if generation fails.

## Request body

- object
  - `musicId` string, uuid — A completed song from `POST /music`. Provide this OR `musicAssetId`, not both.
  - `musicAssetId` string, uuid — A track uploaded with `POST /uploads` (purpose `music`). Provide this OR `musicId`, not both.
  - `visualMode` 'ai-images' | 'ai-video' | 'cover-image', required — `ai-images` (a new AI image every few seconds), `ai-video` (short AI clips), or `cover-image` (one still for the whole song).
  - `visualDirection` string — Optional art direction for the visuals, e.g. "neon cyberpunk city at night, moody". Mention a saved element by @handle (see `GET /elements`) to reuse it, e.g. "@Robo-Cat on a rooftop". Its photo is fed to the image model so it looks the same in every scene it appears in. Each mentioned element adds a reference charge per scene for `ai-images`.
  - `imageStyleId` string — Image style for `ai-images`/`ai-video`. Get IDs from `GET /image-styles`.
  - `imageQuality` 'basic' | 'good' | 'premium' | 'max' — Image quality for `ai-images` (higher costs more).
  - `secondsPerImage` number — For `ai-images`: how many seconds each image is shown. Fewer seconds means more images and more credits.
  - `videoQuality` 'basic' | 'good' | 'premium' | 'max' — Clip quality for `ai-video` (higher costs more).
  - `coverImageAssetId` string, uuid — For `cover-image` mode: an image uploaded with `POST /uploads` (purpose `element-image`). Required for that mode.
  - `aspectRatio` '9:16' | '16:9' | '1:1' — Video dimensions.
  - `captionsEnabled` boolean — Show word-synced lyric captions. Automatically off for instrumental tracks.
  - `captionStyleId` string — Caption style ID from `GET /caption-styles`.
  - `captionPosition` 'top' | 'center' | 'bottom' — Where captions sit on screen.
  - `showWaveform` boolean — Show an audio waveform animation.
  - `musicTrimStartSeconds` number — Start the video at this point in the song (seconds). Defaults to the start.
  - `musicTrimEndSeconds` number — End the video at this point in the song (seconds). Defaults to the full length.

## Response `200`

OK

- object
  - `videoId` string, uuid, required — Poll `GET /videos/{id}`. When completed, export with POST /exports.
  - `status` 'pending', required
  - `estimatedCredits` number, required — Credits reserved. Settled to the actual cost or refunded when generation ends.

## Other responses

- `401` — 401
- `402` — 402
- `403` — 403

## Changes

- **2026-08-28** `f2531c657594` — 1 info
  - added the new `max` enum value to the request property `videoQuality`
- **2026-08-22** `35448566f143` — 1 warning
  - removed the request property `elementId`
- **2026-08-22** `d28bfadc0adc` — 1 info
  - added the new optional request property `elementId`
- **2026-08-15** `ac1de8fd0dfc` — 1 breaking, 2 info
  - the `oneOf[subschema #1]/data` response's property type/format changed from ``/`` to `object`/`` for status `403`
  - the response property `oneOf[subschema #1]/data` became required for the status `403`
  - added the required property `oneOf[subschema #1]/data/feature` to the response with the `403` status

[Change history](https://skmtc.dev/aituber/apis/aituber-api/changes/music-videos/post.md)

---

[API](https://skmtc.dev/aituber/apis/aituber-api.md) · [All operations](https://skmtc.dev/aituber/apis/aituber-api/llms.txt) · [OpenAPI document](https://skmtc-service-production.skmtc.workers.dev/v1/apis/aituber/aituber-api/revisions/f2531c657594/schema)
