> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.beatapi.io/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.beatapi.io/_mcp/server.

# Music Video

> Create a Music Video workflow task from images, audio, and creative controls.

`POST https://api.beatapi.io/v1/music-video/tasks`

Create a Music Video workflow task from images, audio, and creative controls.

## Authorization

`Authorization`   `string`   **required**

Send your BeatAPI API key as a Bearer token. Create one on the [Dashboard](https://beatapi.io/dashboard).

```
Authorization: Bearer <BEATAPI_API_KEY>
```

Keep permanent API keys on trusted servers. `Content-Type: application/json` is required for the request body. `Idempotency-Key` is optional when the endpoint exposes it and is recommended for safe retries with the exact same body.

## Request body

`mv_tier`   `enum<string>`   **optional**

Select the Music Video tier. Omit this field for Standard; Premium requests must set `premium`.

**Available options:** `standard`, `premium`  \
**Default:** `"standard"`

---

`images`   `string[]`   **optional**

Top-level scene images. Standard requires 1-7. Premium sing modes accept 0-6; Premium dance and perform require exactly 6 public HTTPS PNG, JPEG, or WebP URLs.

**Count:** 0 to 7 items

---

`audio_url`   `string`   **required**

Top-level public HTTPS audio URL. Standard accepts 10-180 seconds; Premium accepts 10-300 seconds.

**Format:** `uri`

---

`prompt`   `string`   **optional**

Optional creative direction for story, setting, performance, camera, lighting, and pacing. Maximum 3000 characters.

**Length:** at most 3000 characters

---

`language`   `enum<string>`   **optional**

Dialogue and lyric language used by the Standard workflow.

**Available options:** `en`, `zh`

---

`quality`   `enum<string>`   **optional**

Generation quality tier. High quality is unavailable at 540p.

**Available options:** `standard`, `high`  \
**Default:** `"standard"`

---

`style`   `string`   **optional**

Optional concise visual style, such as cinematic, anime, documentary, or fashion editorial.

**Length:** at most 200 characters

---

`aspect_ratio`   `enum<string>`   **optional**

Target output placement. Set explicitly for the destination player or social feed.

**Available options:** `1:1`, `16:9`, `9:16`, `4:3`, `3:4`

---

`resolution`   `enum<string>`   **optional**

Top-level output resolution. Standard accepts 540p, 720p, or 1080p; Premium is fixed to 720p.

**Available options:** `540p`, `720p`, `1080p`  \
**Default:** `"720p"`

---

`lip_sync`   `boolean`   **optional**

Generate lip-synchronized performance. When true, `lip_ref_url` is required.

**Default:** `false`

---

`lip_ref_url`   `string`   **optional**

Public HTTPS close-up, front-facing face image used for Standard lip sync.

**Format:** `uri`

---

`add_subtitle`   `boolean`   **optional**

Burn generated or supplied subtitles into the final video.

**Default:** `false`

---

`subtitle_color`   `string`   **optional**

Subtitle text color as a six-digit hexadecimal value. Used when subtitles are enabled.

---

`srt_url`   `string`   **optional**

Optional public HTTPS `.srt` subtitle file. Upload a local subtitle through `POST /v1/files`.

**Format:** `uri`

---

`duration`   `integer`   **optional**

Top-level billing fallback only; detected audio duration wins. Standard accepts 10-180 seconds and Premium accepts 10-300 seconds.

**Range:** 10 to 300

---

`compose_mode`   `enum<string>`   **optional**

Auto composes the final Music Video; manual pauses at `requires_action` so shots can be reviewed or edited before compose.

**Available options:** `auto`, `manual`  \
**Default:** `"auto"`

---

`mv_mode`   `enum<string>`   **optional**

Premium performance mode. Sing modes require `lip_ref_urls`; dance and perform require exactly six `images`.

**Available options:** `sing`, `sing_perform`, `dance`, `perform`

---

`lip_ref_urls`   `string[]`   **optional**

Required for sing and sing_perform; omit for dance and perform. Provide one or two public HTTPS close-up, front-facing face images.

**Count:** 1 to 2 items

## Response

A successful request returns HTTP `201`.

```json
{
  "data": {
    "id": "task_8K2qA",
    "object": "task",
    "task_kind": "workflow",
    "capability_id": "music-video",
    "capability_version": 1,
    "workflow": "music-video",
    "status": "queued",
    "stage": "queued",
    "storyboard": {
      "shots": []
    },
    "created_at": 1782210000,
    "updated_at": 1782210000,
    "completed_at": null,
    "output": null,
    "usage": {
      "credits_reserved": 1.5,
      "credits_charged": 1.5,
      "billable_duration_seconds": 15,
      "credits_settled": 0,
      "credits_refunded": 0
    },
    "request_id": "req_abc123",
    "error_code": null,
    "error_message": null
  }
}
```

## Manual review workflow

When `compose_mode` is `manual`, poll until the task reaches `requires_action`, then use the returned storyboard and shot IDs:

1. Call `POST /v1/music-video/tasks/{task_id}/shots/{shot_id}/edit` when a shot prompt or Premium reference images need adjustment.
2. Call `GET /v1/music-video/tasks/{task_id}/shots/{shot_id}/media` when you need a hosted preview for review.
3. Call `POST /v1/music-video/tasks/{task_id}/compose` after the selected shots are ready.

Keep polling the same parent task after edit or compose operations. Automatic composition does not require these manual calls.

## Next step

Save `data.id` from the accepted response and poll `GET /v1/tasks/{task_id}` every 5–10 seconds until `status` is `succeeded` or `failed`. Read finished assets from `data.output.media`.

## Errors

| Status | Meaning                                                                                                                                                                                                                                                                                    |
| ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `400`  | Malformed JSON or a field, value or combination this endpoint does not accept (`bad_request`; the message names the field), or input refused by moderation (`content_policy_violation`). Not retryable unchanged.                                                                          |
| `401`  | No API key (`missing_api_key`), or a key that is wrong, expired, disabled or exhausted (`invalid_api_key`; the message says which). Send it as `Authorization: Bearer <key>`; the key works with or without the `sk-` prefix. Not retryable.                                               |
| `402`  | Insufficient balance (`insufficient_credits`). The account balance is zero or below the price of this request. Top up, then send it again; not retryable before that.                                                                                                                      |
| `403`  | The key or account is not permitted to make this call (`forbidden`), for example a model that is not available on free credit (a top-up unlocks it), a request from outside the key's IP allowlist, or a model outside the key's group. Not retryable.                                     |
| `409`  | The `Idempotency-Key` was already used with a different request body or path within 24 hours, or the first request with it is still running (`idempotency_conflict`). Not retryable unchanged.                                                                                             |
| `429`  | Too many requests (`rate_limit_exceeded`, including the free-model limits). Retryable after `Retry-After` seconds (also `error.retry_after_seconds`).                                                                                                                                      |
| `500`  | Unexpected internal error (`internal_error`). Retryable; keep `request_id` for support if it persists.                                                                                                                                                                                     |
| `503`  | The request could not be completed (`processing_unavailable`, `processing_timeout`, `processing_failed` or `result_transfer_failed`). Nothing was charged. Retryable with backoff; a 503 carries no `Retry-After` header and no `retry_after_seconds`. BeatAPI does not answer 502 or 504. |