> ## Documentation Index
> Fetch the complete documentation index at: https://docs.apimart.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Gemini Omni 1.2 Flash Video Generation

> Generate from text or images, use subject references and first/last frames, edit or extend videos. Up to 4K, 24fps, with audio.

> [!NOTE]
>
> Text-to-video and image-to-video support 3–15 whole seconds, default 10. First/last-frame interpolation and the added segment of an extension support up to 10 seconds. Editing ignores `duration` and preserves the source video length. Video input defaults to editing; extension requires `"omni_reference_task_type": "extend"`.

```bash cURL theme={null}
curl --request POST \
  --url https://api.apimart.ai/v1/videos/generations \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: application/json' \
  --data '{
    "model": "gemini-omni-1.2-flash",
    "prompt": "A marble rolling fast on a chain reaction style track, continuous smooth shot.",
    "aspect_ratio": "16:9",
    "resolution": "720p",
    "duration": 15
  }'
```

```python Python theme={null}
import time
import requests

base_url = "https://api.apimart.ai"
headers = {"Authorization": "Bearer <token>"}
payload = {
    "model": "gemini-omni-1.2-flash",
    "prompt": "A marble rolling fast on a chain reaction style track, continuous smooth shot.",
    "aspect_ratio": "16:9",
    "resolution": "720p",
    "duration": 15,
}
response = requests.post(
    f"{base_url}/v1/videos/generations",
    headers=headers, json=payload, timeout=30,
)
response.raise_for_status()
task_id = response.json()["data"][0]["task_id"]
print(task_id)

deadline = time.monotonic() + 600
while time.monotonic() < deadline:
    response = requests.get(
        f"{base_url}/v1/tasks/{task_id}", headers=headers, timeout=30,
    )
    response.raise_for_status()
    task = response.json()["data"]
    if task["status"] == "completed":
        print(task["result"]["videos"][0]["url"][0])
        break
    if task["status"] == "failed":
        raise RuntimeError(task["error"]["message"])
    time.sleep(5)
else:
    raise TimeoutError(f"Continue polling task {task_id}")
```

```javascript JavaScript theme={null}
const baseUrl = "https://api.apimart.ai";
const headers = {
  Authorization: "Bearer <token>",
  "Content-Type": "application/json",
};
const response = await fetch(`${baseUrl}/v1/videos/generations`, {
  method: "POST",
  headers,
  signal: AbortSignal.timeout(30_000),
  body: JSON.stringify({
    model: "gemini-omni-1.2-flash",
    prompt: "A marble rolling fast on a chain reaction style track, continuous smooth shot.",
    aspect_ratio: "16:9",
    resolution: "720p",
    duration: 15,
  }),
});
if (!response.ok) throw new Error(await response.text());
const taskId = (await response.json()).data[0].task_id;
console.log(taskId);

async function waitForTask(taskId) {
  const deadline = Date.now() + 600_000;
  while (Date.now() < deadline) {
    const response = await fetch(`${baseUrl}/v1/tasks/${taskId}`, {
      headers,
      signal: AbortSignal.timeout(30_000),
    });
    if (!response.ok) throw new Error(await response.text());
    const task = (await response.json()).data;
    if (task.status === "completed") return task.result.videos[0].url[0];
    if (task.status === "failed") throw new Error(task.error.message);
    await new Promise(resolve => setTimeout(resolve, 5000));
  }
  throw new Error(`Continue polling task ${taskId}`);
}
console.log(await waitForTask(taskId));
```

```json 200 theme={null}
{
  "code": 200,
  "data": [
    {
      "status": "submitted",
      "task_id": "task_01EXAMPLE"
    }
  ]
}
```

## Authentication

**Authorization** `string` *required*

Use Bearer token authentication. Get a key from the [API Key management page](https://apimart.ai/keys). Submit requests with `Content-Type: application/json`.

## Request parameters

**model** `string` *required*

Must be `gemini-omni-1.2-flash`.

**prompt** `string` *required*

Required text instructions: describe the scene for text-to-video, or the motion, style, or changes for image-to-video, editing, and extension. You must provide `prompt` even when supplying reference images, first/last frames, video, or `extend_from_task_id`. Omitting it returns HTTP 400.

**duration** `integer` (default: 10)

Output duration for text-to-video and image-to-video as an integer from `3` to `15`, default `10`. First/last-frame interpolation and extension support only `3`–`10` seconds. For extension, this is the added segment length; the returned video includes both the original and added segments. Editing ignores `duration` and preserves the source video length. Parameter values outside the allowed range fail the task with `invalid_duration`.

**resolution** `string` (default: 720p)

`360p` / `720p` / `1080p` / `4k`, case-insensitive; `2160p` is treated as `4k`. `1080p` and `4k` are upsampled. Resolution affects output token usage and the reserved amount. Other values fail the task with `invalid_resolution`.

**aspect\_ratio** `string` (default: 16:9)

Only `16:9` (landscape, default) and `9:16` (portrait). Other values are treated as `16:9`.

**image\_urls** `string[]`

Reference images as publicly accessible HTTP(S) direct image URLs only. Data URLs and Base64 are not supported. One image defaults to the starting frame; multiple images act as subject references. Up to 10 images in total, including first/last frames. For character references, use at most 2 characters with up to 3 images each, preferably no more than 6 images overall.

**first\_frame\_image** `string`

Starting frame. Used alone, generation starts from this image; with `last_frame_image`, it enables first/last-frame interpolation. Only publicly accessible HTTP(S) direct image URLs are supported.

**last\_frame\_image** `string`

Ending frame; requires `first_frame_image`, otherwise the task fails with `invalid_frame_images`. Use the same ratio for both frames and match `aspect_ratio`. Only publicly accessible HTTP(S) direct image URLs are supported.

**image\_with\_roles** `object[]`

Images with roles, an alternative to the direct first/last-frame fields. Choose one way to specify the frames. All images used count toward the total limit of 10.

**Array item**

**url** `string` *required*

Only publicly accessible HTTP(S) direct image URLs are supported.

**role** `string` *required*

`first_frame` specifies the starting frame and `last_frame` the ending frame; other roles are references. An ending frame requires a starting frame.

**video\_urls** `string[]`

Video to edit or extend: at most 1 clip, no longer than 15 seconds. Only publicly accessible HTTP(S) direct video URLs are supported. Data URLs and Base64 are not supported. Video input defaults to editing.

**omni\_reference\_task\_type** `string` (default: auto)

Task type: `auto` (default, inferred from the input) / `edit` (editing) / `extend` (extension) / `reference` (multiple image references). Also accepts `text_to_video` / `image_to_video` / `reference_to_video`. When omitted or set to `auto`, both `video_urls` and `extend_from_task_id` default to editing; extension requires an explicit `extend` value.

**extend\_from\_task\_id** `string`

Reference your own previous generation task ID to reuse its video without uploading it again. Defaults to editing. With `"omni_reference_task_type": "extend"`, adds a segment of up to 10 seconds at the end.

## Capabilities and limits

* Output is 24fps video with dialogue, music, or sound effects. Describe the desired audio in `prompt`.
* Audio input, system prompts, `temperature`, and negative-prompt parameters are not supported. Put negative instructions directly in `prompt`.
* Upstream regional restrictions: in the EEA, Switzerland, and the UK, editing or extending uploaded videos and editing images containing minors are not supported.
* All output contains an invisible SynthID watermark.

## Examples

Submit each JSON body to `POST /v1/videos/generations`. Replace example media URLs and task IDs with your own usable inputs.

### 15-second 4K portrait video

```json theme={null}
{
  "model": "gemini-omni-1.2-flash",
  "prompt": "Aerial shot over a misty mountain lake at sunrise, birds flying, slow forward camera move.",
  "aspect_ratio": "9:16",
  "resolution": "4k",
  "duration": 15
}
```

### Image-to-video and subject references

```json theme={null}
{
  "model": "gemini-omni-1.2-flash",
  "prompt": "The cat playfully bats at the ball of yarn.",
  "image_urls": [
    "https://example.com/cat.png",
    "https://example.com/yarn.png"
  ],
  "duration": 12
}
```

### First/last-frame interpolation

```json theme={null}
{
  "model": "gemini-omni-1.2-flash",
  "prompt": "Smooth transition, camera slowly pushes in.",
  "first_frame_image": "https://example.com/start.jpg",
  "last_frame_image": "https://example.com/end.jpg",
  "aspect_ratio": "16:9",
  "duration": 8
}
```

### Specifying frames with image roles

```json theme={null}
{
  "model": "gemini-omni-1.2-flash",
  "prompt": "A smooth cinematic transition from sunrise to a starry night.",
  "image_with_roles": [
    {
      "url": "https://example.com/sunrise.jpg",
      "role": "first_frame"
    },
    {
      "url": "https://example.com/night.jpg",
      "role": "last_frame"
    }
  ],
  "duration": 8
}
```

### Video editing

```json theme={null}
{
  "model": "gemini-omni-1.2-flash",
  "prompt": "Make the violin invisible. Keep everything else the same.",
  "video_urls": [
    "https://example.com/clip.mp4"
  ]
}
```

Editing preserves the source video length; `duration` has no effect.

Use short, specific editing instructions. For a local change, add `Keep everything else the same`.

### Extending a previous task

```json theme={null}
{
  "model": "gemini-omni-1.2-flash",
  "prompt": "The camera continues panning across the mountains.",
  "extend_from_task_id": "task_01PREVIOUS",
  "omni_reference_task_type": "extend",
  "duration": 8
}
```

To extend an uploaded video, replace `extend_from_task_id` with `video_urls` and keep `"omni_reference_task_type": "extend"`. The returned video contains the original followed by the added segment. `duration` controls only the added length, up to 10 seconds, and only the added seconds are billed. For example, a 5-second source with `duration: 4` returns a video of about 9 seconds.

## Submission response and task status

A successful submission returns HTTP 200; read `data[0].task_id`. Poll the [task status endpoint](https://docs.apimart.ai/en/api-reference/tasks/status.md) every 5–10 seconds until `completed` or `failed`. Allow 10 minutes overall. If your client times out, keep querying the original task instead of submitting it again.

```bash theme={null}
curl --request GET \
  --url https://api.apimart.ai/v1/tasks/task_01EXAMPLE \
  --header 'Authorization: Bearer <token>'
```

Timing examples: a 15-second 360p video takes about 30 seconds; a 15-second 4K video takes about 5 minutes. These are estimates; use task status as the authority.

```json theme={null}
{
  "code": 200,
  "data": {
    "id": "task_01EXAMPLE",
    "status": "completed",
    "progress": 100,
    "result": {
      "videos": [
        {
          "url": [
            "https://cdn.example.com/gemini_omni_video.mp4"
          ]
        }
      ]
    }
  }
}
```

`data` in the query response is the task object. `data.result.videos[0].url` is an array; the first video URL is `data.result.videos[0].url[0]`. Download or play it directly, and archive it for long-term storage. `data.cost` is the final charge in USD.

| Status | Action |
| - | - |
| `pending` / `processing` | Keep polling; check `data.progress` for progress. |
| `completed` | Read and save the video URL. |
| `failed` | Read `data.error.message`; failed tasks are not charged. |

## Billing and reserved balance

Token-based billing: resolution affects video output tokens per second. For text-to-video and image-to-video, `duration` specifies the output length. Editing ignores it and preserves the source video length; extension uses it only for the added segment. See [APIMart pricing](https://apimart.ai/pricing) for actual rates.

At submission, balance is reserved using the resolution and `max(10, duration)` seconds; video input is estimated at 15 seconds. This reservation is not the final charge. After success, it is adjusted to actual usage; read `data.cost` for the final amount.

Extension is charged only for added seconds. Failed tasks are not charged. Insufficient balance for the reservation returns HTTP 402.

## Error handling

Parameter errors (`invalid_*` / `unsupported_*`) immediately set the task to `failed` without a charge. Check task status even after successful submission.

| Error / status | Cause and action |
| - | - |
| `invalid_duration` | `duration` is outside 3–15, or interpolation / extension exceeds 10 seconds. Use an integer within the allowed range. |
| `invalid_task_type` | Unsupported `omni_reference_task_type`. Use `auto` / `edit` / `extend` / `reference`; `text_to_video` / `image_to_video` / `reference_to_video` are also accepted. |
| `invalid_resolution` | Use `360p` / `720p` / `1080p` / `4k`; `2160p` is also accepted. |
| `invalid_frame_images` | Only an ending frame was provided. Add a starting frame. |
| `unsupported_image_count` | More than 10 images including first/last frames. Reduce the count. |
| `unsupported_video_count` | More than 1 input video. Keep one clip no longer than 15 seconds. |
| `HTTP 400` | Missing required `prompt`. Provide text instructions even when supplying media. |
| `HTTP 401` | Invalid key. Check Authorization. |
| `HTTP 402` | Insufficient balance for the reservation. Top up or lower the resolution. |
| `HTTP 429` | Rate limit reached. Retry with backoff. |
| `status: failed` | Upstream failure or content-policy rejection. Read `data.error.message` and adjust the request. |

## FAQ

### Is `prompt` required when I provide images or video?

Yes. Every mode requires `prompt`, including image-to-video, first/last-frame interpolation, editing, extension, and video reuse through `extend_from_task_id`. Omitting this field returns HTTP 400.

### Can I send Base64 images or video directly?

No. `image_urls`, `first_frame_image`, `last_frame_image`, `image_with_roles[].url`, and `video_urls` accept only publicly accessible HTTP(S) direct URLs. Do not send `data:image/...`, `data:video/...`, or raw Base64 strings.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.