# Generate video

> Start a video render on an explicit model, with optional frame inputs, and collect the file.

`POST /video/generate` creates a video task. `model` and `prompt` are
required. One request renders one video, and there is no `auto` or `count`.

**SDK**

```ts
import Mynth from "@mynthio/sdk";

const mynth = new Mynth();

const task = await mynth.video.generate({
  model: "bytedance/seedance-2.0-mini",
  prompt: "A lighthouse beam sweeping over waves",
  duration: 5,
  size: "9:16_720p",
});

console.log(task.urls[0]);
```

**REST**

```bash
curl https://api.mynth.io/video/generate \
  -H "Authorization: Bearer $MYNTH_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"bytedance/seedance-2.0-mini","prompt":"A lighthouse beam sweeping over waves","duration":5,"size":"9:16_720p"}'
```

The REST call returns a `task_id` and `estimated_cost` at once. The SDK waits up
to an hour. A render takes minutes, so in a request handler, create the task
with `generateAsync()` and finish in a [webhook](https://mynth.io/docs/concepts/webhooks.md)
instead of waiting. The CLI has no video command.

## Fields

| Field                          | Notes                                                                                                                       |
| ------------------------------ | --------------------------------------------------------------------------------------------------------------------------- |
| `model`                        | Required. An id from [video models](https://mynth.io/docs/models/video.md)                                                                     |
| `prompt`                       | Required. 1 to 8192 characters                                                                                              |
| `negative_prompt`              | Optional. Up to 8192 characters                                                                                             |
| `size`                         | Aspect ratio and resolution tier. Defaults to `auto`. See [sizes](#sizes)                                                   |
| `duration`                     | Seconds. Defaults to the model's default. Each model accepts its own range                                                  |
| `audio`                        | Generated audio. Defaults to the model's default, which is on for every current model                                       |
| `inputs`                       | Frame images. See [frame inputs](#frame-inputs)                                                                             |
| `webhook`                      | Per-request URLs, same shape as on images. See [webhooks](https://mynth.io/docs/concepts/webhooks.md#per-request-webhooks)                     |
| `metadata`                     | A JSON object up to 2048 bytes                                                                                              |
| `generate_public_access_token` | `true` returns a browser token as `public_access_token`. See [from a browser](https://mynth.io/docs/guides/poll-for-results.md#from-a-browser) |

Video does not take `destination`, `count`, `magic_prompt`, or `output`. Sending any of them answers `400 validation_error`.

Every value is checked against the model when the task is created. A
resolution tier, duration, audio setting, or input the model does not serve
answers `400 validation_error`, and nothing is queued.

## Sizes

You ask for a shape and a resolution tier, not pixels. The shapes are the same
as for [images](https://mynth.io/docs/guides/generate-images.md#sizes), and Mynth picks the
closest aspect ratio the model serves. The tier is not adjusted: it sets the
price, so a tier the model does not serve answers `400 validation_error`.

| `size`                                                                                | Result                                           |
| ------------------------------------------------------------------------------------- | ------------------------------------------------ |
| `auto`, or no `size`                                                                  | the model's default shape and tier               |
| `square`, `portrait`, `landscape`, `portrait_tall`, `landscape_wide`                  | 1:1, 2:3, 3:2, 9:16, 16:9                        |
| `1:1`, `2:3`, `3:2`, `3:4`, `4:3`, `4:5`, `5:4`, `9:16`, `16:9`, `21:9`, `2:1`, `1:2` | that ratio                                       |
| Any of the above with `_480p`, `_720p`, `_1080p`, or `_4k`, such as `9:16_1080p`      | that shape at that tier                          |
| `{ "type": "aspect_ratio", "aspect_ratio": "9:16", "resolution": "1080p" }`           | the same, as an object. `resolution` is optional |
| `{ "type": "auto", "resolution": "1080p" }`                                           | the model's default shape at that tier           |

With a first frame, the frame sets the shape and the aspect ratio is ignored.
The tier still applies. The result's `aspect_ratio` is the ratio the video was
rendered at, or `null` when the frame set it.

## Frame inputs

Send `inputs` to animate from an image. Each input is a URL string or an
object with a role:

```json
{
  "model": "bytedance/seedance-2.0-mini",
  "prompt": "The camera pulls back from the lighthouse",
  "inputs": [
    {
      "type": "image",
      "as": "first_frame",
      "source": { "type": "url", "url": "https://cdn.example.com/start.png" }
    },
    {
      "type": "image",
      "as": "last_frame",
      "source": { "type": "url", "url": "https://cdn.example.com/end.png" }
    }
  ]
}
```

Every current model needs exactly one `first_frame` for image-to-video.
Seedance and Gemini Omni Flash also take an optional `last_frame`. P-Video and
Grok Imagine Video take the first frame only. [Video models](https://mynth.io/docs/models/video.md)
has the table, and `modes` on the catalog entry is the live contract.

## What comes back

```json
{
  "model": "bytedance/seedance-2.0-mini",
  "videos": [
    {
      "status": "success",
      "id": "vid_3HkP9wQz7LmR2tXc8VbN5dFy0JsA4gUe",
      "url": "https://cdn.mynth.io/videos/vid_3HkP9wQz7LmR2tXc8VbN5dFy0JsA4gUe.mp4",
      "mynth_url": "https://cdn.mynth.io/videos/vid_3HkP9wQz7LmR2tXc8VbN5dFy0JsA4gUe.mp4",
      "cost": "0.40500000",
      "duration": 5,
      "resolution": "720p",
      "aspect_ratio": "9:16",
      "audio": true
    }
  ]
}
```

Check `status` on the video. A refusal or a provider failure fails the item
with an `error.code` while the task still completes. The file is served for 7
days. See [tasks](https://mynth.io/docs/concepts/tasks.md#file-lifetimes).

## Price

Video is `per_second[tier] × duration`, where `tier` is the resolution in
`size`, and the estimate is exact because
the model is explicit. Price a body with `POST /video/generate/estimate`, or
`mynth.video.estimate()` in the SDK. [Pricing](https://mynth.io/docs/pricing.md#video-price) has
the formula.

## Next steps

- [Video models](https://mynth.io/docs/models/video.md): resolutions, durations, and frame inputs per model.
- [Webhooks](https://mynth.io/docs/concepts/webhooks.md): collect a long render without holding a connection.
- [Poll for results](https://mynth.io/docs/guides/poll-for-results.md): the status and result calls.
