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

# Article to Video Example

> Turn blog posts and news articles into narrated videos

## Overview

Article to Video reads a web page, turns its text into a narration split into scenes, reads it with a voice and puts a visual under each scene. Use it to repurpose your blog, summarise industry news or turn documentation pages into short explainers.

Every request needs `sourceUrl` (a public `https://` page) and `voiceId` (from `GET /v1/voice/list`). `summaryType` is `summarize` (default), `summarize_long` or `key_as_is`; with the first two `targetDuration` sets the length (default 30 seconds, 10 to 600). `mediaType` defaults to `ai-images`.

<Note>
  The create call answers in a few seconds with the `projectId` and status `processing`. The article is read and summarised after that, then the video is generated and rendered. If the page cannot be read or summarised, the project becomes `failed` (the reason is in `message`), the credits come back and your webhook gets the failure.
</Note>

## A short summary with AI images

`customPrompt` steers the summary (only with `summarize`).

```javascript theme={null}
const response = await fetch('https://api.hooked.so/v1/project/create/article-to-video', {
  method: 'POST',
  headers: {
    'x-api-key': process.env.HOOKED_API_KEY,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    sourceUrl: 'https://example.com/blog/remote-work-tips',
    voiceId: '1000',
    summaryType: 'summarize',
    targetDuration: 45,
    customPrompt: 'Three tips, one per scene, for people new to remote work',
    mediaType: 'ai-images',
    presetSettings: { preset: 'cinematic' },
    musicId: '15',
    aspectRatio: 'ratio_9_16',
    caption: { preset: 'tiktok', alignment: 'bottom' },
    webhook: 'https://yoursite.com/hooked-webhook?token=YOUR_SECRET',
    metadata: { postSlug: 'remote-work-tips' }
  })
});

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

## The whole article, with AI video clips

`key_as_is` keeps the article's content and order; the video is as long as the text needs and `targetDuration` is ignored.

```javascript theme={null}
const response = await fetch('https://api.hooked.so/v1/project/create/article-to-video', {
  method: 'POST',
  headers: {
    'x-api-key': process.env.HOOKED_API_KEY,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    sourceUrl: 'https://example.com/news/space-mission-launch',
    voiceId: '1000',
    summaryType: 'key_as_is',
    mediaType: 'ai-videos',
    presetSettings: { preset: 'realistic', quality: 'pro' },
    aspectRatio: 'ratio_16_9',
    webhook: 'https://yoursite.com/hooked-webhook?token=YOUR_SECRET'
  })
});
```

## Over your own footage or gameplay

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

response = requests.post(
    "https://api.hooked.so/v1/project/create/article-to-video",
    headers={"x-api-key": os.environ["HOOKED_API_KEY"]},
    json={
        "sourceUrl": "https://example.com/blog/history-of-coffee",
        "voiceId": "1000",
        "summaryType": "summarize_long",
        "targetDuration": 90,
        "mediaType": "gameplay",
        "gameplaySettings": {"selectedGame": "minecraft", "selectedVideo": "minecraft-3"},
        "webhook": "https://yoursite.com/hooked-webhook?token=YOUR_SECRET",
    },
)

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

For your own footage send `mediaType: "media"` and the library IDs in `media`.

## 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, Firecrawl (to read the page) and ElevenLabs (the narration) 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 [Article to Video reference](/api-reference/video/article-to-video) for every field and error.


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