> ## 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.

# Clone Video Example

> Remake a TikTok, Instagram or YouTube video with your voice and new AI visuals

## Overview

Clone Video takes a short video that already works and makes a new one like it: Hooked analyses the source's story, structure and pacing, writes a new narration, reads it with your voice and generates a new visual for each scene. Use it to adapt a trend to your brand, test a competitor's format with your own message, or turn one video into several variations.

Every request needs `sourceVideoUrl` (a TikTok, Instagram or YouTube link) and `voiceId` (from `GET /v1/voice/list`). The look is taken from the source video, so there is no style preset: `mediaType` is `ai-images` (default) or `ai-videos`. `targetDurationSeconds` sets the length (default 30 seconds) and `mustInclude` something the new video has to mention. The create call answers with a `projectId`; the video arrives later.

## From a TikTok, with AI images

```javascript theme={null}
const response = await fetch('https://api.hooked.so/v1/project/create/clone-video', {
  method: 'POST',
  headers: {
    'x-api-key': process.env.HOOKED_API_KEY,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    sourceVideoUrl: 'https://www.tiktok.com/@hooked.so/video/7412345678901234567',
    voiceId: '1000',
    targetDurationSeconds: 30,
    mustInclude: 'Mention our 14-day free trial at the end',
    mediaType: 'ai-images',
    aspectRatio: 'ratio_9_16',
    caption: { preset: 'tiktok', alignment: 'bottom' },
    webhook: 'https://yoursite.com/hooked-webhook?token=YOUR_SECRET',
    metadata: { source: 'trend-board' }
  })
});

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

## From a YouTube Short, with AI video clips

With `ai-videos` the clips are chained frame to frame. `presetSettings.quality` picks the clip model (`base`, `pro` by default, `ultra`), or name one with `presetSettings.aiModel`.

```javascript theme={null}
const response = await fetch('https://api.hooked.so/v1/project/create/clone-video', {
  method: 'POST',
  headers: {
    'x-api-key': process.env.HOOKED_API_KEY,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    sourceVideoUrl: 'https://www.youtube.com/shorts/aBcD1234EfG',
    voiceId: '1000',
    targetDurationSeconds: 45,
    mediaType: 'ai-videos',
    presetSettings: { aiModel: 'seedance_2_0_fast' },
    musicId: '15',
    webhook: 'https://yoursite.com/hooked-webhook?token=YOUR_SECRET'
  })
});
```

## Several variations of one Reel

Each request is a new project (and is charged as one). Send them one by one and keep each `projectId`:

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

angles = [
    "Mention the free shipping offer",
    "Mention the new spring colours",
    "Mention the 30-day returns",
]

for angle in angles:
    response = requests.post(
        "https://api.hooked.so/v1/project/create/clone-video",
        headers={"x-api-key": os.environ["HOOKED_API_KEY"]},
        json={
            "sourceVideoUrl": "https://www.instagram.com/reel/C9xYz123AbC/",
            "voiceId": "1000",
            "mustInclude": angle,
            "webhook": "https://yoursite.com/hooked-webhook?token=YOUR_SECRET",
        },
    )
    print(angle, response.json()["data"]["projectId"])
```

## 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`. A source that cannot be read (private, deleted, region-locked) makes the project fail; the webhook is called with `"status": "FAILED"` and the credits are refunded.

<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 and ElevenLabs in Settings → AI keys (and Gemini for the Omni Flash model). A missing key answers `402 missing_credentials` with the list in `missingProviders`, before anything is created.
</Note>

See the [Clone Video reference](/api-reference/video/clone-video) for every field and error.


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