# Article to video — Veedio API workflow

- Canonical URL: https://www.veedio.co/docs/workflows/article-to-video
- Markdown source: https://www.veedio.co/docs/workflows/article-to-video.md
- Parent index: https://www.veedio.co/faq-for-llms.md
- Last updated: September 2026

A link, read and turned into a short: an article, a video, a post, a thread or a PDF.

## Endpoint

`POST https://www.veedio.co/api/v1/videos` with `workflow: "article-to-video"`. Authenticate with
`Authorization: Bearer vd_live_...` (also accepted: `x-api-key`, `x-veedio-api-key`, `key`).

## Required input

`source.url` — An http(s) URL, up to 2,000 characters. It is fetched and the script is held to what it says: an article or product page (title, outline and text), a YouTube video (its captions, or its description), a post on X, a Reddit thread (the post and top comments), a LinkedIn post, or a PDF (its text). In the app the read happens before the job is queued, so an unreadable link answers 400 with the reason; through the API it happens in the worker, so the generation fails with that reason instead.

## Defaults for this workflow

- voice: rachel
- captions: bold-center
- music: uplifting
- style: cinematic
- ratio: 9:16

## Minimal request

```json
{
  "workflow": "article-to-video",
  "source": {
    "url": "https://en.wikipedia.org/wiki/Honey"
  }
}
```

## Full example

```bash
curl -X POST https://www.veedio.co/api/v1/videos \
  -H "Authorization: Bearer $VEEDIO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "workflow": "article-to-video",
  "source": {
    "url": "https://en.wikipedia.org/wiki/Honey"
  },
  "title": "What honey actually is",
  "voice": "rachel",
  "captionStyle": "bold-center",
  "musicTrack": "cinematic",
  "visualStyle": "documentary",
  "aspectRatio": "9:16"
}'
```

## Parameters

| Field | Type | Required | Default | Allowed | Description |
| --- | --- | --- | --- | --- | --- |
| `source.url` | string | yes |  |  | An http(s) URL, up to 2,000 characters. It is fetched and the script is held to what it says: an article or product page (title, outline and text), a YouTube video (its captions, or its description), a post on X, a Reddit thread (the post and top comments), a LinkedIn post, or a PDF (its text). In the app the read happens before the job is queued, so an unreadable link answers 400 with the reason; through the API it happens in the worker, so the generation fails with that reason instead. |
| `source.text` | string | no |  |  | Ignored by this workflow unless `source.url` is missing, in which case the text is read as the URL. |
| `title` | string | no | `Untitled video` |  | Up to 120 characters. Shown in the app, and used as the caption when you publish without one. |
| `preset` | string | no |  |  | A tool page's slug — `top-5-video-generator`, `storytime-video-generator`, `explainer-video-generator` and 50 others at https://www.veedio.co/tools. The page's format brief is put in front of your source before the script is written, so the video comes out in that shape. The brief itself is resolved here from the slug and is never accepted as text; an unknown slug answers 400. Each page's own brief is quoted verbatim at https://www.veedio.co/tools/{slug}/llms.txt. |
| `voice` | string | no | `rachel` | `rachel`, `adam`, `bella`, `josh`, `elli` | The narrator. Scene length is this voice's real duration, not an estimate. All five speak every one of the 29 languages — set `language` and the same voice reads it. |
| `captionStyle` | string | no | `bold-center` | `bold-center`, `highlight`, `subtle`, `none` | Captions are word-timed from the voice model's own character alignment and burned into the MP4. `none` renders the video without them. |
| `musicTrack` | string | no | `uplifting` | `none`, `uplifting`, `lofi`, `cinematic`, `trap` | A licensed track, ducked under the narration and loudness-normalised with it. `none` leaves the voice alone. |
| `visualStyle` | string | no | `cinematic` | `cinematic`, `3d`, `anime`, `documentary`, `retro`, `toy`, `voxel`, `clay`, `comic`, `watercolor` | Appended to the image prompt for every scene, so the whole video holds one look. Applies to generated frames; see mediaType for stock footage. |
| `mediaType` | string | no | `animated on paid plans, still on Free` | `animated`, `filmed`, `still`, `stock`, `avatar` | What each scene is made of. The credit per scene follows the choice; the deposit and the settlement both use it. `animated` and `filmed` need a paid plan and answer 403 on Free. `stock` is offered only where the deployment has a Pexels key, and answers 400 otherwise. |
| `avatarId` | string | no |  |  | For `avatar`: which presenter, by the provider's avatar id. The create form lists them; through the API, `GET /api/avatars` does (a signed-in session, not a key). |
| `soundEffects` | boolean | no | `false` |  | A generated sound effect under each scene, cued by the script writer and mixed under the narration. 2 credits a scene. Starter and up; answers 403 on Free. |
| `photoUrl` | string | no |  |  | An http(s) link to a picture the video opens on: scene one uses it as its frame instead of a drawn one, set in motion by whatever the media type does. Any public JPEG, PNG or WebP; private addresses are refused. |
| `quality` | string | no | `standard` | `standard`, `pro` | The model tier. `pro` draws frames with the sharper image model (3 more a scene) and, for `animated` and `filmed`, sets them moving with the premium video model (38 more). It does nothing for stock footage. |
| `motionModel` | string | no | `kling` | `seedance`, `kling`, `veo` | Which premium video model animates the scenes at `pro` quality. Ignored at `standard`. Choosing one needs the Pro plan or above and answers 403 below it; leaving it out is every plan's right. The credit per scene follows the clip the model is asked for, priced at its longest: Seedance — the default — adds 5 for ten seconds, Kling 38 for ten, Veo 45 for eight. A shorter scene is charged pro rata. |
| `language` | string | no | `en` | `en`, `es`, `pt-BR`, `fr`, `de`, `it`, `nl`, `pl`, `sv`, `da`, `fi`, `cs`, `sk`, `ro`, `el`, `bg`, `hr`, `uk`, `ru`, `tr`, `ar`, `hi`, `ta`, `id`, `ms`, `fil`, `ja`, `ko`, `zh` | The narration and caption language. The script is written in it and the voice speaks it; image prompts stay in English. Every language is on every plan. |
| `targetSeconds` | integer | no | `60` | `30`, `60`, `90`, `180` | How long the script should run: 30, 60, 90 or 180. The scene range the writer is asked for follows it, and so does the deposit. Over 60 needs a paid plan and answers 403 on Free. A single video may cost at most 1600 credits, whatever the length. |
| `aspectRatio` | string | no | `9:16` | `9:16`, `1:1`, `16:9` | The render is 1080-class in every ratio, with no watermark on any plan. |

## Response

`202 Accepted`. The row exists; the video does not yet.

```json
{
  "id": "8f1c0f2e-8a4d-4f2b-9e2c-2f1a0b7c9d31",
  "status": "queued",
  "creditsEstimated": 68,
  "url": "https://www.veedio.co/videos/8f1c0f2e-8a4d-4f2b-9e2c-2f1a0b7c9d31"
}
```

Poll `GET https://www.veedio.co/api/v1/videos/{id}` every few seconds until `status` is
`ready` or `failed`. There is no completion webhook yet.

## Credits

A generation costs 3 credits plus a charge per scene that follows what fills it: 2 for a still or stock footage, 13 for a scene the video model sets in motion. A 5-scene short is 13 credits with stills and 68 animated.
Quote a job for free with `POST https://www.veedio.co/api/v1/credits/estimate`; the deposit is
reconciled the moment the scenes are written, and an abandoned generation is refunded in full.

## Notes

- **The page is really fetched.** `readSource()` picks a reader from the link — article, YouTube transcript, X, Reddit, TikTok, Instagram, LinkedIn or PDF — and the script writer is told to use only what that page says.
- A page behind a login, a paywall or a hard bot wall cannot be read. For those, paste the text into `script-to-video` instead: it costs the same and says what you meant.
- `http(s)` only. A URL sent in `source.text` is still read as the source for this workflow.

## Recipes

### Newsroom cut

Documentary look, deeper narrator, cinematic bed — closer to a news short than a TikTok.

```json
{
  "workflow": "article-to-video",
  "source": {
    "url": "https://example.com/blog/quarterly-update"
  },
  "visualStyle": "documentary",
  "voice": "adam",
  "musicTrack": "cinematic"
}
```

## Related

- All workflows: https://www.veedio.co/docs/workflows/prompt-to-video, https://www.veedio.co/docs/workflows/script-to-video, https://www.veedio.co/docs/workflows/idea-to-video, https://www.veedio.co/docs/workflows/article-to-video
- Endpoint reference: https://www.veedio.co/docs/api-reference
- MCP server: https://www.veedio.co/mcp
- CLI: https://www.veedio.co/docs/cli
- Machine index: https://www.veedio.co/llms.txt
