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

# Music to Video Example

> Turn songs into music videos whose visuals follow the lyrics

## Overview

Music to Video transcribes a song's lyrics and builds a music video around them: a visual for each part of the song, cut to the beat, with the lyrics as captions. The song plays as the soundtrack.

Send the song as a direct `https://` link to the audio file in `audioUrl` (MP3, M4A, AAC, WAV or OGG, up to 10 MB; Hooked downloads it) or as a `musicId` from your library. The video follows the lyrics, so the song needs vocals.

<Note>
  The create call downloads the song and checks it is audio, then answers with the `projectId` and status `processing`. The transcription, the visuals and the render happen after that. If a step fails, the project becomes `failed` (the reason is in `message`), the credits come back and your webhook gets the failure.
</Note>

## AI images in a style

```javascript theme={null}
const response = await fetch('https://api.hooked.so/v1/project/create/music-to-video', {
  method: 'POST',
  headers: {
    'x-api-key': process.env.HOOKED_API_KEY,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    audioUrl: 'https://example.com/music/summer-nights.mp3',
    mediaType: 'ai-images',
    presetSettings: { preset: 'anime' },
    visualGuidelines: 'A road trip along the coast at sunset, warm colors',
    addSoundWave: true,
    aspectRatio: 'ratio_9_16',
    caption: { preset: 'tiktok' },
    webhook: 'https://yoursite.com/hooked-webhook?token=YOUR_SECRET',
    metadata: { trackId: 'summer-nights' }
  })
});

const { data } = await response.json();
console.log('Project ID:', data.projectId); // status: "processing"
```

## AI video clips, chained

Each clip starts on the last frame of the one before with `isContinuous`. `language` tells the transcription which language the lyrics are in (it is detected when omitted).

```python theme={null}
import os
import requests

response = requests.post(
    "https://api.hooked.so/v1/project/create/music-to-video",
    headers={"x-api-key": os.environ["HOOKED_API_KEY"]},
    json={
        "audioUrl": "https://example.com/music/midnight-drive.m4a",
        "mediaType": "ai-videos",
        "presetSettings": {"preset": "cinematic", "quality": "pro", "isContinuous": True},
        "aspectRatio": "ratio_16_9",
        "language": "es",
        "webhook": "https://yoursite.com/hooked-webhook?token=YOUR_SECRET",
    },
)

print(response.json()["data"]["projectId"])
```

## Over gameplay

```bash theme={null}
curl -X POST "https://api.hooked.so/v1/project/create/music-to-video" \
  -H "x-api-key: $HOOKED_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "audioUrl": "https://example.com/music/level-up.mp3",
    "mediaType": "gameplay",
    "gameplaySettings": { "selectedGame": "minecraft", "selectedVideo": "minecraft-2" },
    "caption": { "preset": "beast", "alignment": "middle" },
    "addSoundWave": false
  }'
```

## A song already in Hooked

`musicId` takes a track from [`GET /v1/music/list`](/api-reference/music/list) or one of your team's own audio files, instead of `audioUrl`. The file is copied for the video. Most library tracks are instrumental: use a song with vocals.

## When the song is refused

| Answer | What to do |
| - | - |
| `400 audioUrl: The file is not an MP3, M4A, AAC, WAV or OGG audio file` | The link answers a page (Spotify, YouTube, a Suno song page, a viewer) instead of the file: use the direct link to the audio file. |
| `400 audioUrl: The audio file is larger than 10 MB` | Export a smaller file (an MP3 at 192 kbps fits about 7 minutes). |
| `400 audioUrl: Must be a public https URL (…)` | The host is private, local or redirects to one. |
| `403 Insufficient storage …` | Free some space in your media library. |

Nothing is charged for any of these.

## Getting the video

Wait for the webhook or poll [`GET /v1/project/{projectId}`](/api-reference/project/details) until `video.status` is `COMPLETED`, then download `video.url`.

<Warning>
  Send an [`Idempotency-Key`](/guides/idempotency) header to retry safely: if a request times out or answers 5xx, sending it again with the same key and body returns the first answer instead of creating (and charging) the project twice.
</Warning>

<Note>
  Teams in **bring-your-own-keys** mode are not charged credits, but need OpenRouter in Settings → AI keys (and Gemini for the Omni Flash model). No ElevenLabs key: nothing is narrated. A missing key answers `402 missing_credentials` with the list in `missingProviders`, before anything is created.
</Note>

See the [Music to Video](/api-reference/video/music-to-video) reference for every field and error.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.