> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.simplified.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.simplified.com/_mcp/server.

# Media · Generate · Generate AI video

POST https://api.simplified.com/api/v2/ai-video/generate
Content-Type: application/json

Generate an AI video from a prompt, an image, two frames, several
images, or a source video. One call: POST `{model, parameters}`
(`capability` is optional — derived from which inputs you send).
It **blocks and returns the final result** — do not poll. Use the
input slot names below as-is for every model; the server adapts the
payload to the model you chose. If something does not fit that model
(a ratio, duration or resolution it lacks, too many images for the
mode), the error says exactly what to change. `getModelFields`
(`type=video`) is optional — call it only when you want the model's
duration/resolution options before choosing.

## Why `task_id` is misleading here

The endpoint also returns a `task_id`, but it tracks the *submission*
Celery task that hands the request off to FAL/Kie — it flips to
SUCCESS almost immediately, well before the actual video is rendered.
**Do not call `getTaskResult` on this `task_id`** — it tells you
nothing useful about generation completion. Always poll
`getVideoVariation` instead. The apikit middleware strips `task_id`
from this response automatically to avoid confusion.

## Storage modes

* `default` — persists into the AiImageArt gallery (recommended).
* `transient` — generated without surfacing in the gallery; useful
  for one-shot agent runs.
* `asset` — saves the rendered video as a standalone reusable
  `TldrAsset` (no gallery entry).

Reference: https://docs.simplified.com/api-reference/platform/ai-generation/generate-video

## Authentication

- `Authorization` header (required) (prefixed with ` Api-Key   `) — Header authentication of the form `Api-Key  <token>`
- `Authorization` header (bearer token, required) — Bearer authentication of the form `Bearer <token>`, where token is your auth token.

## Request

### Body (application/json)

This endpoint expects an object.

- `model` (string, required, default: K25TP) — Engine id. Currently registered engines: `BOH15` (OmniHuman 1.5 — lipsync: person image + speech audio → talking video dubbed verbatim; output duration = audio duration, ≤60s @720p / ≤30s @1080p; reference_image only; params: `image_url`, `audio_url`, optional `prompt`/`resolution`/ `turbo_mode`/`mask_url` — no duration/aspect_ratio), `BSD2` (Seedance 2.0 — text/image/first-last/multi, 480p–1080p, audio), `BSD2F` (Seedance 2.0 Fast — same modes, 720p max), `BSD25` (Seedance 2.5 — text/image/first-last/multi/video→video), `K30` (Kling 3.0 — text/image/first-last, std/pro/4K, 3–15s), `KV3TT` (Kling V3 Turbo text-to-video, 720p/1080p, 3–15s), `KV3TI` (Kling V3 Turbo image-to-video, 720p/1080p, 3–15s), `GT2V` (Grok Imagine text-to-video, 6–30s, 480p/720p), `GI2V` (Grok Imagine image-to-video, 6–30s, 480p/720p), `W27T` (WAN 2.7 text-to-video, neg-prompt, 720p/1080p, 2–15s), `W27I` (WAN 2.7 image+first-last-frame, 720p/1080p, 2–15s), `MH23P` (MiniMax Hailuo 2.3 Pro image-to-video, 768P/1080P, 6s/10s), `MH23S` (MiniMax Hailuo 2.3 Std image-to-video, 768P/1080P, 6s/10s), `GOMNI` (Gemini Omni — text/image/multi/v2v, 4–10s, 720p/1080p/4K), `K25TP` (Kling 2.5 Turbo Pro — text+image, 5s/10s), `K25TS` (Kling 2.5 Turbo Std — image-to-video, 5s/10s), `MH02S` (MiniMax Hailuo 02 Std — text/image/first-last, 6s/10s), `MH02P` (MiniMax Hailuo 02 Pro — text/image/first-last, 6s), `MH02F` (MiniMax Hailuo 02 Fast — image-to-video, 6s/10s), `W25P` (WAN 2.5 Preview — text+image, 5s/10s, neg-prompt), `VEO31` (VEO 3.1 — text/image/multi/first-last, 4–8s, audio), `VEO31F` (VEO 3.1 Fast — same capabilities, faster), `VEO31L` (VEO 3.1 Lite — text/image/first-last). Call `getModelFields` with `type=video` and no `model_id` to get the live list with capabilities and parameter schemas.
- `parameters` (ApiV2AiVideoGeneratePostRequestBodyContentApplicationJsonSchemaParameters, required) — Always a nested object — these keys never go at the top level. Input slots use the same names on every model; each takes an **asset UUID** from this workspace (from a previous generateImage/createAsset/uploadAsset call), not a raw URL. Engine-specific options (`duration`, `resolution`, `mode`, `negative_prompt`, `generate_audio`) are validated against the chosen model; a value it lacks is rejected with the supported list.
- `capability` (enum, optional) — Optional. Derived from the inputs when omitted: a source video → video_to_video; first/last frames → first_last_frame; several images → multiple_images; one image → reference_image; none → prompt. Set it only to force a mode; a mode the model lacks is rejected by name.
  - Allowed values: `prompt`, `reference_image`, `multiple_images`, `first_last_frame`, `video_to_video`
- `storage` (enum, optional, default: default) — Storage mode for the rendered video — see operation description.
  - Allowed values: `default`, `transient`, `asset`

## Response

### 202

Video generation completed (apikit blocks here until `job_status` is terminal — the post-hook polls the AIArtVariation internally). Final body is the AIArtVariation with `job_status="DONE"`; on terminal failure the body is `{error: true, id, art_variation_id, status, message, payload}`. Useful keys on success: `output.file_url` (rendered video), `output.thumbnail_cover_image`, `id` (variation id), `payload.input` (echo of the request).

- `any`

## Errors

### 400 Bad Request Error

Invalid model, capability, or parameters (does not match the model's field schema).

- `any`

### 401 Unauthorized Error

Unauthorized.

- `any`

### 429 Too Many Requests Error

Quota exceeded — no remaining AI credits.

- `any`

## Types

### ApiV2AiVideoGeneratePostRequestBodyContentApplicationJsonSchemaParameters

Always a nested object — these keys never go at the top level. Input slots use the same names on every model; each takes an **asset UUID** from this workspace (from a previous generateImage/createAsset/uploadAsset call), not a raw URL. Engine-specific options (`duration`, `resolution`, `mode`, `negative_prompt`, `generate_audio`) are validated against the chosen model; a value it lacks is rejected with the supported list.

- `prompt` (string, optional) — What the video should show. Optional for image-driven modes.
- `image_url` (string, optional) — One image to animate (reference_image). Asset UUID.
- `image_urls` (list of string, optional) — Several images composed into one video (multiple_images). Asset UUIDs; the model's count limit is enforced.
- `first_frame_url` (string, optional) — First frame (first_last_frame). Asset UUID.
- `last_frame_url` (string, optional) — Last frame (first_last_frame). Asset UUID.
- `video_url` (string, optional) — Source video (video_to_video). Asset UUID.
- `audio_url` (string, optional) — Speech audio for lipsync models (BOH15). Asset UUID.
- `reference_audio_urls` (list of string, optional) — Reference audio clips where the model supports them (Seedance). Asset UUIDs.
- `aspect_ratio` (enum, optional) — Output aspect ratio. 16:9 and 9:16 work on every engine that takes a ratio; image-driven modes usually take none (it is dropped). A ratio the chosen model lacks is rejected with its supported list. Never invent a ratio.
  - Allowed values: `16:9`, `9:16`, `1:1`, `4:3`, `3:4`, `21:9`, `2:3`, `3:2`, `auto`, `adaptive`

## Examples

**Request**

```json
{
  "model": "VEO31",
  "parameters": {
    "prompt": "A sunrise over snow-capped mountains, cinematic",
    "aspect_ratio": "16:9",
    "duration": 8,
    "generate_audio": true
  },
  "capability": "prompt"
}
```

**SDK Code**

```python AI Generation_generateVideo_example
import requests

url = "https://api.simplified.com/api/v2/ai-video/generate"

payload = {
    "model": "VEO31",
    "parameters": {
        "prompt": "A sunrise over snow-capped mountains, cinematic",
        "aspect_ratio": "16:9",
        "duration": 8,
        "generate_audio": True
    },
    "capability": "prompt"
}
headers = {
    "Authorization": "Api-Key  <apiKey>",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.json())
```

```javascript AI Generation_generateVideo_example
const url = 'https://api.simplified.com/api/v2/ai-video/generate';
const options = {
  method: 'POST',
  headers: {Authorization: 'Api-Key  <apiKey>', 'Content-Type': 'application/json'},
  body: '{"model":"VEO31","parameters":{"prompt":"A sunrise over snow-capped mountains, cinematic","aspect_ratio":"16:9","duration":8,"generate_audio":true},"capability":"prompt"}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go AI Generation_generateVideo_example
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://api.simplified.com/api/v2/ai-video/generate"

	payload := strings.NewReader("{\n  \"model\": \"VEO31\",\n  \"parameters\": {\n    \"prompt\": \"A sunrise over snow-capped mountains, cinematic\",\n    \"aspect_ratio\": \"16:9\",\n    \"duration\": 8,\n    \"generate_audio\": true\n  },\n  \"capability\": \"prompt\"\n}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("Authorization", "Api-Key  <apiKey>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby AI Generation_generateVideo_example
require 'uri'
require 'net/http'

url = URI("https://api.simplified.com/api/v2/ai-video/generate")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Api-Key  <apiKey>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"model\": \"VEO31\",\n  \"parameters\": {\n    \"prompt\": \"A sunrise over snow-capped mountains, cinematic\",\n    \"aspect_ratio\": \"16:9\",\n    \"duration\": 8,\n    \"generate_audio\": true\n  },\n  \"capability\": \"prompt\"\n}"

response = http.request(request)
puts response.read_body
```

```java AI Generation_generateVideo_example
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://api.simplified.com/api/v2/ai-video/generate")
  .header("Authorization", "Api-Key  <apiKey>")
  .header("Content-Type", "application/json")
  .body("{\n  \"model\": \"VEO31\",\n  \"parameters\": {\n    \"prompt\": \"A sunrise over snow-capped mountains, cinematic\",\n    \"aspect_ratio\": \"16:9\",\n    \"duration\": 8,\n    \"generate_audio\": true\n  },\n  \"capability\": \"prompt\"\n}")
  .asString();
```

```php AI Generation_generateVideo_example
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://api.simplified.com/api/v2/ai-video/generate', [
  'body' => '{
  "model": "VEO31",
  "parameters": {
    "prompt": "A sunrise over snow-capped mountains, cinematic",
    "aspect_ratio": "16:9",
    "duration": 8,
    "generate_audio": true
  },
  "capability": "prompt"
}',
  'headers' => [
    'Authorization' => 'Api-Key  <apiKey>',
    'Content-Type' => 'application/json',
  ],
]);

echo $response->getBody();
```

```csharp AI Generation_generateVideo_example
using RestSharp;

var client = new RestClient("https://api.simplified.com/api/v2/ai-video/generate");
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "Api-Key  <apiKey>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"model\": \"VEO31\",\n  \"parameters\": {\n    \"prompt\": \"A sunrise over snow-capped mountains, cinematic\",\n    \"aspect_ratio\": \"16:9\",\n    \"duration\": 8,\n    \"generate_audio\": true\n  },\n  \"capability\": \"prompt\"\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift AI Generation_generateVideo_example
import Foundation

let headers = [
  "Authorization": "Api-Key  <apiKey>",
  "Content-Type": "application/json"
]
let parameters = [
  "model": "VEO31",
  "parameters": [
    "prompt": "A sunrise over snow-capped mountains, cinematic",
    "aspect_ratio": "16:9",
    "duration": 8,
    "generate_audio": true
  ],
  "capability": "prompt"
] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://api.simplified.com/api/v2/ai-video/generate")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```