# Video

> Video generation.

Video generation.

When and why to call these: the [video guide](https://docs.lumavox.ai/media/videos.md).

## Generate a video

`POST /v1/videos`

Accepts the request, charges for it and returns immediately with a `gen_…` id. Poll `GET /v1/videos/{id}`; a clip takes minutes.

**Charged when accepted**, per second at a rate that depends on `resolution`; a failure is refunded in full. Give `start_frame` (and `end_frame`) to animate images from your library. **There is a limit on how many of your videos may be unfinished at once** — the platform's `limits.org.active_generations.video` (`GET /v1/platform/limits`): over it, this answers 429 without charging anything.

```bash title="curl"
curl -X POST "https://api.lumavox.ai/v1/videos" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"prompt":"..."}'
```

**Request body** (`application/json`)

| Field | Type | Required | Description |
|---|---|---|---|
| `prompt` | string | yes | What should happen in the clip. 1–4000 characters. |
| `aspect_ratio` | string |  | One of: 21:9, 2:1, 16:9, 4:3, 1:1, 3:4, 9:16. Note this is **not** the same set images accept — video adds `2:1`. Default `"16:9"`. |
| `duration` | integer |  | Whole seconds. **This is what you are charged on** — the price is per second at a rate that depends on `resolution`. 5–20. Default `5`. |
| `resolution` | string |  | One of: hd, fhd. `hd` is 720p and `fhd` is 1080p, and they are **priced differently per second**. Default `"hd"`. |
| `generate_audio` | boolean |  | Default `true`. |
| `safety_tolerance` | integer |  | 0 is strictest. **The ceiling is 4 here, not the 5 images allow.** 0–4. Default `2`. |
| `start_frame` | string or null |  | `ast_…` — an image in your library to open the clip on. Omit for text-to-video. |
| `end_frame` | string or null |  | `ast_…` — an image to close the clip on, pinned at `duration`. **Requires `start_frame`**. |
| `folder_id` | string or null |  | `fld_…` — the folder in your asset library the finished file is filed under. Omit it for the root. A folder that is not yours is a 400, never a silent fall back to the root. |

**Responses**

| Status | Description |
|---|---|
| `202` | `application/json` — Accepted and charged. Poll `GET /v1/videos/{id}` |
| `400` | The request could not be read: malformed JSON |
| `401` | Missing or invalid credentials |
| `402` | Out of credits, or the organisation is suspended — nothing was charged |
| `403` | The key is valid but its scopes do not cover this capability — a key limited to `tts` gets this from `/v1/images` rather than a 401 |
| `422` | The request failed validation |
| `429` | Rate limit exceeded |
| `503` | The capability's provider is not configured here |

**`202` response body**

| Field | Type | Description |
|---|---|---|
| `id` | string | `gen_…`. Poll this. |
| `status` | `"queued"`, `"submitted"`, `"running"`, `"succeeded"`, `"failed"`, `"moderated"` | `queued`, `submitted` and `running` mean keep polling. `succeeded`, `failed` and `moderated` are terminal — stop. |
| `capability` | `"tts"`, `"image"`, `"video"`, `"stt"`, `"skybox"` |  |
| `model` | string or null |  |
| `prompt` | string or null |  |
| `aspect_ratio` | string or null |  |
| `width` | integer or null |  |
| `height` | integer or null |  |
| `output_format` | string or null |  |
| `seed` | integer or null |  |
| `megapixels` | number or null |  |
| `safety_tolerance` | integer or null |  |
| `enhance_prompt` | boolean or null |  |
| `folder_id` | string or null | `fld_…` the result lands in, or null for the root. |
| `duration` | integer or null | Seconds asked for. Video only. |
| `resolution` | string or null | `hd` or `fhd`. Video only. |
| `generate_audio` | boolean or null |  |
| `start_frame` | string or null |  |
| `end_frame` | string or null |  |
| `negative_text` | string or null |  |
| `style_id` | integer or null |  |
| `init_image` | string or null |  |
| `init_strength` | number or null |  |
| `voice_id` | string or null |  |
| `speech` | TTSOptions or null | The voice and model a speech generation ran with. |
| `speech.voice_id` | string | An id from `GET /v1/voices` — the built-in voice, a platform voice, or one your organisation uploaded. |
| `speech.model` | string | Which model speaks: one of the voice's `models` in `GET /v1/voices` — `eleven_flash_v2_5` (the fastest, and the default), `eleven_multilingual_v2` or `eleven_v3`. A model the voice does not list is refused. |
| `speech.provider_options` | ProviderVoiceSettingsInfo or null | The provider's voice settings sent on top of the voice's own; `null` took theirs. |
| `speech.provider_options.stability` | number or null | Low is more expressive and less consistent between generations; high is flatter and more repeatable. |
| `speech.provider_options.similarity_boost` | number or null | How closely to cling to the original voice. High can reproduce artefacts in the source. |
| `speech.provider_options.style` | number or null | Style exaggeration. Costs latency; leave unset on anything conversational. |
| `speech.provider_options.use_speaker_boost` | boolean or null | Similarity at the cost of latency. |
| `speech.provider_options.speed` | number or null | 1.0 is the voice's own pace. |
| `speech.format` | `"wav"`, `"pcm"` |  |
| `speech.sample_rate` | `8000`, `16000`, `22050`, `24000`, `44100` or null | Hz of the returned audio — one of 8000, 16000, 22050, 24000, 44100, each served natively by the provider. Unset means 24000. `POST /v1/tts` says what it produced in the `X-Sample-Rate` header. Queued speech (`POST /v1/audio`) does not take it: each of its formats has its own rate. |
| `credits_micros` | integer or null | What was debited when this was accepted, in micro-credits (1 credit is 1,000,000). A failure refunds it in full; a transcription's is corrected to the measured length when it finishes. |
| `template_id` | string or null |  |
| `image` | GenerationImage or null |  |
| `image.asset_id` | string or null | The library entry this generation produced. |
| `image.url` | string or null | A short-lived link to the file. Minted per response and not stored — fetch the asset again for a fresh one. |
| `image.width` | integer or null |  |
| `image.height` | integer or null |  |
| `image.content_type` | string or null |  |
| `image.size_bytes` | integer or null |  |
| `video` | GenerationVideo or null |  |
| `video.asset_id` | string or null | The library entry this generation produced. |
| `video.url` | string or null | A short-lived link to the file. Minted per response and not stored — fetch the asset again for a fresh one. |
| `video.width` | integer or null |  |
| `video.height` | integer or null |  |
| `video.duration_seconds` | number or null |  |
| `video.content_type` | string or null |  |
| `video.size_bytes` | integer or null |  |
| `video.has_thumbnail` | boolean or null |  |
| `audio` | GenerationAudio or null |  |
| `audio.asset_id` | string or null | The library entry this generation produced. |
| `audio.url` | string or null | A short-lived link to the file. Minted per response and not stored — fetch the asset again for a fresh one. |
| `audio.duration_seconds` | number or null |  |
| `audio.content_type` | string or null |  |
| `audio.size_bytes` | integer or null |  |
| `audio.peaks` | array of integer or null | Waveform magnitudes, 0-100, for a mirrored strip; null when never computed. |
| `transcript` | GenerationTranscript or null |  |
| `transcript.text` | string or null | The transcript, as one string. |
| `transcript.language_code` | string or null |  |
| `transcript.language_probability` | number or null |  |
| `transcript.duration_seconds` | number or null |  |
| `transcript.word_count` | integer or null |  |
| `transcript.asset_id` | string or null | The library entry holding the full JSON. |
| `transcript.content_type` | string or null |  |
| `transcript.size_bytes` | integer or null |  |
| `transcript.url` | string or null |  |
| `skybox` | GenerationSkybox or null |  |
| `skybox.asset_id` | string or null | The library entry this generation produced. |
| `skybox.url` | string or null | A short-lived link to the file. Minted per response and not stored — fetch the asset again for a fresh one. |
| `skybox.preview_url` | string or null | A short-lived link to the 2K WebP, which is what to load in a 360 viewer. |
| `skybox.width` | integer or null |  |
| `skybox.height` | integer or null |  |
| `skybox.content_type` | string or null |  |
| `skybox.size_bytes` | integer or null |  |
| `skybox.has_thumbnail` | boolean or null |  |
| `skybox.files` | array of SkyboxFile | Every file the environment was stored as, in plan order. |
| `skybox.files[].name` | string | `hdr-4k`, `hdr-2k`, `png-8k`, `png-4k`, `png-2k`, `preview-2k`, `depth-2k`. |
| `skybox.files[].content_type` | string |  |
| `skybox.files[].url` | string or null | Short-lived link. Minted per response and not stored. |
| `skybox.files[].width` | integer or null |  |
| `skybox.files[].height` | integer or null |  |
| `skybox.files[].size_bytes` | integer or null |  |
| `error` | string or null |  |
| `created_at` | string (date-time) |  |
| `finished_at` | string (date-time) or null |  |

## Check a video

`GET /v1/videos/{generation_id}`

```bash title="curl"
curl "https://api.lumavox.ai/v1/videos/$GENERATION_ID" \
  -H "Authorization: Bearer $API_KEY"
```

**Path parameters**

| Name | Type | Required | Description |
|---|---|---|---|
| `generation_id` | string | yes |  |

**Responses**

| Status | Description |
|---|---|
| `200` | `application/json` — The generation — the clip once it succeeded |
| `400` | The request could not be read: malformed JSON |
| `401` | Missing or invalid credentials |
| `403` | The key is valid but its scopes do not cover this capability — a key limited to `tts` gets this from `/v1/images` rather than a 401 |
| `404` | No such generation |
| `422` | The request failed validation |
| `429` | Rate limit exceeded |
| `503` | The capability's provider is not configured here |

**`200` response body**

| Field | Type | Description |
|---|---|---|
| `id` | string | `gen_…`. Poll this. |
| `status` | `"queued"`, `"submitted"`, `"running"`, `"succeeded"`, `"failed"`, `"moderated"` | `queued`, `submitted` and `running` mean keep polling. `succeeded`, `failed` and `moderated` are terminal — stop. |
| `capability` | `"tts"`, `"image"`, `"video"`, `"stt"`, `"skybox"` |  |
| `model` | string or null |  |
| `prompt` | string or null |  |
| `aspect_ratio` | string or null |  |
| `width` | integer or null |  |
| `height` | integer or null |  |
| `output_format` | string or null |  |
| `seed` | integer or null |  |
| `megapixels` | number or null |  |
| `safety_tolerance` | integer or null |  |
| `enhance_prompt` | boolean or null |  |
| `folder_id` | string or null | `fld_…` the result lands in, or null for the root. |
| `duration` | integer or null | Seconds asked for. Video only. |
| `resolution` | string or null | `hd` or `fhd`. Video only. |
| `generate_audio` | boolean or null |  |
| `start_frame` | string or null |  |
| `end_frame` | string or null |  |
| `negative_text` | string or null |  |
| `style_id` | integer or null |  |
| `init_image` | string or null |  |
| `init_strength` | number or null |  |
| `voice_id` | string or null |  |
| `speech` | TTSOptions or null | The voice and model a speech generation ran with. |
| `speech.voice_id` | string | An id from `GET /v1/voices` — the built-in voice, a platform voice, or one your organisation uploaded. |
| `speech.model` | string | Which model speaks: one of the voice's `models` in `GET /v1/voices` — `eleven_flash_v2_5` (the fastest, and the default), `eleven_multilingual_v2` or `eleven_v3`. A model the voice does not list is refused. |
| `speech.provider_options` | ProviderVoiceSettingsInfo or null | The provider's voice settings sent on top of the voice's own; `null` took theirs. |
| `speech.provider_options.stability` | number or null | Low is more expressive and less consistent between generations; high is flatter and more repeatable. |
| `speech.provider_options.similarity_boost` | number or null | How closely to cling to the original voice. High can reproduce artefacts in the source. |
| `speech.provider_options.style` | number or null | Style exaggeration. Costs latency; leave unset on anything conversational. |
| `speech.provider_options.use_speaker_boost` | boolean or null | Similarity at the cost of latency. |
| `speech.provider_options.speed` | number or null | 1.0 is the voice's own pace. |
| `speech.format` | `"wav"`, `"pcm"` |  |
| `speech.sample_rate` | `8000`, `16000`, `22050`, `24000`, `44100` or null | Hz of the returned audio — one of 8000, 16000, 22050, 24000, 44100, each served natively by the provider. Unset means 24000. `POST /v1/tts` says what it produced in the `X-Sample-Rate` header. Queued speech (`POST /v1/audio`) does not take it: each of its formats has its own rate. |
| `credits_micros` | integer or null | What was debited when this was accepted, in micro-credits (1 credit is 1,000,000). A failure refunds it in full; a transcription's is corrected to the measured length when it finishes. |
| `template_id` | string or null |  |
| `image` | GenerationImage or null |  |
| `image.asset_id` | string or null | The library entry this generation produced. |
| `image.url` | string or null | A short-lived link to the file. Minted per response and not stored — fetch the asset again for a fresh one. |
| `image.width` | integer or null |  |
| `image.height` | integer or null |  |
| `image.content_type` | string or null |  |
| `image.size_bytes` | integer or null |  |
| `video` | GenerationVideo or null |  |
| `video.asset_id` | string or null | The library entry this generation produced. |
| `video.url` | string or null | A short-lived link to the file. Minted per response and not stored — fetch the asset again for a fresh one. |
| `video.width` | integer or null |  |
| `video.height` | integer or null |  |
| `video.duration_seconds` | number or null |  |
| `video.content_type` | string or null |  |
| `video.size_bytes` | integer or null |  |
| `video.has_thumbnail` | boolean or null |  |
| `audio` | GenerationAudio or null |  |
| `audio.asset_id` | string or null | The library entry this generation produced. |
| `audio.url` | string or null | A short-lived link to the file. Minted per response and not stored — fetch the asset again for a fresh one. |
| `audio.duration_seconds` | number or null |  |
| `audio.content_type` | string or null |  |
| `audio.size_bytes` | integer or null |  |
| `audio.peaks` | array of integer or null | Waveform magnitudes, 0-100, for a mirrored strip; null when never computed. |
| `transcript` | GenerationTranscript or null |  |
| `transcript.text` | string or null | The transcript, as one string. |
| `transcript.language_code` | string or null |  |
| `transcript.language_probability` | number or null |  |
| `transcript.duration_seconds` | number or null |  |
| `transcript.word_count` | integer or null |  |
| `transcript.asset_id` | string or null | The library entry holding the full JSON. |
| `transcript.content_type` | string or null |  |
| `transcript.size_bytes` | integer or null |  |
| `transcript.url` | string or null |  |
| `skybox` | GenerationSkybox or null |  |
| `skybox.asset_id` | string or null | The library entry this generation produced. |
| `skybox.url` | string or null | A short-lived link to the file. Minted per response and not stored — fetch the asset again for a fresh one. |
| `skybox.preview_url` | string or null | A short-lived link to the 2K WebP, which is what to load in a 360 viewer. |
| `skybox.width` | integer or null |  |
| `skybox.height` | integer or null |  |
| `skybox.content_type` | string or null |  |
| `skybox.size_bytes` | integer or null |  |
| `skybox.has_thumbnail` | boolean or null |  |
| `skybox.files` | array of SkyboxFile | Every file the environment was stored as, in plan order. |
| `skybox.files[].name` | string | `hdr-4k`, `hdr-2k`, `png-8k`, `png-4k`, `png-2k`, `preview-2k`, `depth-2k`. |
| `skybox.files[].content_type` | string |  |
| `skybox.files[].url` | string or null | Short-lived link. Minted per response and not stored. |
| `skybox.files[].width` | integer or null |  |
| `skybox.files[].height` | integer or null |  |
| `skybox.files[].size_bytes` | integer or null |  |
| `error` | string or null |  |
| `created_at` | string (date-time) |  |
| `finished_at` | string (date-time) or null |  |
