# Videos

A video moves through four stages: create (credits charged), generate (poll status), render (free, produces the MP4) and publish (free). This guide walks the whole lifecycle; [publishing and scheduling](/developers/docs/publishing-and-scheduling) covers the last stage in depth.

## Models and cost

Pick the model in `POST /videos`. Credits are charged at creation, not at render:

| Model | Credits | What you get |
| --- | --- | --- |
| `storyboard` | 20 | Static AI scenes with motion effects |
| `motion_lite` | 50 | Animated transitions between scenes |
| `motion_pro` | 100 | Cinematic AI motion video |

`GET /options?kind=models` returns the same catalog with costs, so an agent can decide programmatically.

## 1. Create (POST /videos, scope videos:write)

Send a finished narration script and a voice id (from `GET /voices`). Optional fields: `style`, `language`, `name`, `enableBackgroundMusic`, `masterStyle`, `globalNegativePrompt`.

```bash
curl -s -X POST https://faceless.so/api/v1/videos \
  -H "Authorization: Bearer $FACELESS_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"script": "Did you know the ocean has lakes and rivers of its own? ...", "voiceId": "EXAVITQu4vr4xnSDxMaL", "model": "storyboard"}'
```

Response (`201`):

```json
{
  "success": true,
  "data": {
    "id": "665f1b2a9c31a2b3c4d5e801",
    "name": "Did you kn...",
    "model": "storyboard",
    "status": "processing",
    "creditsUsed": 20,
    "statusUrl": "/api/v1/videos/665f1b2a9c31a2b3c4d5e801/status"
  }
}
```

Common errors: `402 insufficient_credits` (top up before retrying), `403 usage_limit_reached` (plan project limit, upgrade to create more), `429 rate_limited` (10 creations per 60s per key; wait for `Retry-After`).

## 2. Poll generation (GET /videos/{id}/status, scope videos:read)

Generation is asynchronous and typically takes a few minutes. Poll every 10 to 30 seconds until `status` is `completed` or `failed`:

```bash
curl -s https://faceless.so/api/v1/videos/665f1b2a9c31a2b3c4d5e801/status \
  -H "Authorization: Bearer $FACELESS_API_KEY"
```

```json
{
  "success": true,
  "data": { "id": "665f1b2a9c31a2b3c4d5e801", "status": "processing", "percentCompleted": 62, "readyForEditing": false, "errorMessages": [], "renderedVideoUrl": null }
}
```

On `failed`, read `errorMessages` for the reason. With the CLI, `faceless videos create --wait` and `faceless videos status <id>` handle the polling.

## 3. Render (POST /videos/{id}/render, scope videos:write)

Rendering assembles the final MP4 in the cloud. It is free (credits were charged at creation) and requires generation to be `completed` first.

```bash
curl -s -X POST https://faceless.so/api/v1/videos/665f1b2a9c31a2b3c4d5e801/render \
  -H "Authorization: Bearer $FACELESS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"codec": "h264"}'
```

The `202` response contains a `renderId`. Poll `GET /renders/{renderId}` (scope videos:read) every 5 to 15 seconds; renders typically finish in under two minutes:

```bash
curl -s https://faceless.so/api/v1/renders/abcd1234efgh \
  -H "Authorization: Bearer $FACELESS_API_KEY"
```

```json
{
  "success": true,
  "data": { "renderId": "abcd1234efgh", "status": "done", "overallProgress": 1, "url": "https://exports.faceless.so/renders/665f1b2a9c31a2b3c4d5e801/1722333444555.mp4" }
}
```

`status` is `in-progress` (with `overallProgress` 0 to 1), `done` (with the MP4 `url`) or `error`. The MP4 `url` is a direct download; it also appears as `renderedVideoUrl` on the video.

## 4. Publish

Publish immediately with `POST /posts`, or set per-platform metadata with `PATCH /videos/{id}` and schedule with `POST /posts/schedule`. Both are free; see [publishing and scheduling](/developers/docs/publishing-and-scheduling).

## Captioning existing footage (POST /videos/captions)

To caption a video or audio file you already have (no AI visuals, no credit cost), send its public URL. Processing is asynchronous; poll `GET /videos/{id}/status` like any other video.

```bash
curl -s -X POST https://faceless.so/api/v1/videos/captions \
  -H "Authorization: Bearer $FACELESS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"videoUrl": "https://example.com/clip.mp4", "language": "English"}'
```

Provide `videoUrl` or `audioUrl` (an audio file becomes a captioned video). Rate limit: 10 per 300s.

## Managing videos

- `GET /videos` (scope videos:read): paginated list, newest first, with `renderedVideoUrl` when available. `?archived=true` for archived only.
- `GET /videos/{id}`: one video with script, voice, model, status and post metadata.
- `PATCH /videos/{id}` (scope videos:write): rename, or set per-platform post metadata before scheduling.
- `DELETE /videos/{id}` (scope videos:write): permanent, no credit refund.

A `404 not_found` on any of these means the id does not exist or belongs to another team.
