# Gemini Omni 1.2 Flash

Gemini Omni 1.2 Flash is Google's multimodal video model for fast generation, conversational editing and cinematic control (updated November 2026). One model ID covers text to video, image to video, first and last frame interpolation, subject references from up to 10 images, editing a video and extending one. Every clip has native sound, runs 3–15 seconds and renders at 360p, 720p, 1080p or 4K. Send the request, keep the returned task ID, and read the finished video from the task. Media goes in as URLs.

## Model IDs

| Model ID                | Modes                                         | Resolutions                   | Length       |
| ----------------------- | --------------------------------------------- | ----------------------------- | ------------ |
| `gemini-omni-1.2-flash` | text, image, frames, references, edit, extend | `360p`, `720p`, `1080p`, `4k` | 3–15 seconds |

See the [model page](https://seedrouter.ai/models/gemini-omni-1-2-flash#pricing) for current prices.

## Quick example

```bash
curl https://api.seedrouter.ai/v1/videos/generations \
  -H "Authorization: Bearer $SEEDROUTER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gemini-omni-1.2-flash",
    "prompt": "A glass marble rolls fast along a wooden chain-reaction track through a sunlit workshop, one continuous smooth tracking shot. No text, no logos.",
    "resolution": "720p",
    "duration": 10,
    "aspect_ratio": "16:9"
  }'
```

```python
import os
import requests

response = requests.post(
    "https://api.seedrouter.ai/v1/videos/generations",
    headers={"Authorization": f"Bearer {os.environ['SEEDROUTER_API_KEY']}"},
    json={
        "model": "gemini-omni-1.2-flash",
        "prompt": "A glass marble rolls fast along a wooden chain-reaction track through a sunlit workshop, one continuous smooth tracking shot. No text, no logos.",
        "resolution": "720p",
        "duration": 10,
        "aspect_ratio": "16:9",
    },
    timeout=60,
)
response.raise_for_status()
task_id = response.json()["id"]
```

```javascript
const response = await fetch('https://api.seedrouter.ai/v1/videos/generations', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.SEEDROUTER_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    model: 'gemini-omni-1.2-flash',
    prompt: 'A glass marble rolls fast along a wooden chain-reaction track through a sunlit workshop, one continuous smooth tracking shot. No text, no logos.',
    resolution: '720p',
    duration: 10,
    aspect_ratio: '16:9',
  }),
});
if (!response.ok) throw new Error(`Request failed: ${response.status}`);
const { id: taskId } = await response.json();
```

```go
package main

import (
    "encoding/json"
    "fmt"
    "net/http"
    "os"
    "strings"
    "time"
)

func main() {
    body := strings.NewReader(`{
      "model": "gemini-omni-1.2-flash",
      "prompt": "A glass marble rolls fast along a wooden chain-reaction track through a sunlit workshop, one continuous smooth tracking shot. No text, no logos.",
      "resolution": "720p",
      "duration": 10,
      "aspect_ratio": "16:9"
    }`)
    req, err := http.NewRequest("POST", "https://api.seedrouter.ai/v1/videos/generations", body)
    if err != nil { panic(err) }
    req.Header.Set("Authorization", "Bearer " + os.Getenv("SEEDROUTER_API_KEY"))
    req.Header.Set("Content-Type", "application/json")
    client := &http.Client{Timeout: 60 * time.Second}
    res, err := client.Do(req)
    if err != nil { panic(err) }
    defer res.Body.Close()
    if res.StatusCode != http.StatusOK { panic(res.Status) }
    var task struct { ID string `json:"id"` }
    if err := json.NewDecoder(res.Body).Decode(&task); err != nil { panic(err) }
    fmt.Println(task.ID)
}
```

## Endpoint

```text
POST https://api.seedrouter.ai/v1/videos/generations
```

| Header        | Value                 |
| ------------- | --------------------- |
| Authorization | `Bearer YOUR_API_KEY` |
| Content-Type  | `application/json`    |

The response is a task (`{"id": "task_...", "status": "processing"}`), not the finished video. Poll `GET /v1/tasks/{task_id}` for the result. Keep API keys in server-side code.

## Parameters

| Field                      | Type        | Default  | Notes                                                                                                                                                    |
| -------------------------- | ----------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `model`                    | string      | required | `gemini-omni-1.2-flash`                                                                                                                                  |
| `prompt`                   | string      | required | Required in every mode: the shot, the change for an edit, or what happens next for an extension. Describe the sound too; put negative instructions here. |
| `duration`                 | integer     | `10`     | 3–15 seconds. At most 10 with first and last frames and for an extension (the added part). Ignored by an edit, which keeps the source length.            |
| `resolution`               | enum        | `720p`   | `360p`, `720p`, `1080p` or `4k` (`2160p` means `4k`), case-insensitive. `1080p` and `4k` are upsampled.                                                  |
| `aspect_ratio`             | enum        | `16:9`   | `16:9` or `9:16`.                                                                                                                                        |
| `image_urls`               | URL list    | none     | One image is the start frame; several are subject references. Up to 10 images in total, frames and role images included.                                 |
| `first_frame_image`        | URL         | none     | The clip opens on this image; with `last_frame_image` the model interpolates between the two.                                                            |
| `last_frame_image`         | URL         | none     | The clip ends on this image. Needs a first frame.                                                                                                        |
| `image_with_roles`         | object list | none     | `{"url", "role"}` with role `first_frame`, `last_frame`, or any other role for a reference. Give frames this way or with the two frame fields, not both. |
| `video_urls`               | URL list    | none     | One clip of at most 15 seconds to edit or extend.                                                                                                        |
| `omni_reference_task_type` | enum        | `auto`   | `auto`, `edit`, `extend`, `reference`, `text_to_video`, `image_to_video` or `reference_to_video`.                                                        |
| `extend_from_task_id`      | string      | none     | The ID of one of your completed `gemini-omni-1.2-flash` tasks, to edit or extend its video without uploading it.                                         |

Every clip comes with sound; there is no sound switch. There is no `negative_prompt`, `seed`, audio input or `callback_url`. The schema is strict: unknown fields are rejected rather than ignored.

## Modes

| Mode                 | How to select it                                                                                            |
| -------------------- | ----------------------------------------------------------------------------------------------------------- |
| Text to video        | No images and no video.                                                                                     |
| Image to video       | One image in `image_urls`, or a first frame.                                                                |
| First and last frame | `first_frame_image` and `last_frame_image`, or the two roles. At most 10 seconds.                           |
| References           | Several images in `image_urls`, or reference roles; `omni_reference_task_type: "reference"` to be explicit. |
| Edit                 | A video in `video_urls` or `extend_from_task_id`; `auto` or `edit`.                                         |
| Extend               | A video as above and `omni_reference_task_type: "extend"`. Adds up to 10 seconds.                           |

A video input edits unless you ask for `extend`; with a video, `reference`, `text_to_video`, `image_to_video` and `reference_to_video` are refused.

### First and last frame

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

### Edit

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

The edit keeps the source length; `duration` has no effect. Short, specific instructions work best; for a local change add "Keep everything else the same".

### Extend an earlier task

```json
{
  "model": "gemini-omni-1.2-flash",
  "prompt": "The camera keeps panning across the mountains.",
  "extend_from_task_id": "task_...",
  "omni_reference_task_type": "extend",
  "duration": 8
}
```

The result contains the original followed by the new part; the new seconds are billed, plus an eighth of the source length. To extend your own clip, send it in `video_urls` instead of `extend_from_task_id`.

## Media inputs

Images and videos are public HTTP(S) URLs. Base64 data URIs are not accepted: upload the files to your own storage and pass their URLs. The video to edit or extend must be at most 15 seconds; its length is read when the request is accepted, and a video whose length cannot be read is rejected before anything is charged.

## Pricing dimensions

Check the [model pricing section](https://seedrouter.ai/models/gemini-omni-1-2-flash#pricing) for current rates. Gemini Omni 1.2 Flash is billed per second of video, at a rate set by the resolution:

```text
text, image, frames, references:  cost = duration × rate
edit:                             cost = (source + source / 8) × rate
extend:                           cost = (added seconds + source / 8) × rate
```

`source` is the input video's picture length rounded up to whole seconds, measured when the request is accepted, so the amount reserved is the amount charged; the eighth covers reading the input video. Examples at 720p: editing a 6.2-second clip bills 7 + 7/8 = 7.875 seconds; extending an 8-second clip by 4 seconds bills 4 + 1 = 5 seconds. Failed tasks are not charged.

## Output schema

Submission returns the task:

```json
{"id": "task_...", "model": "gemini-omni-1.2-flash", "status": "processing", "created_at": 1789689600}
```

### Get the task

```text
GET https://api.seedrouter.ai/v1/tasks/{task_id}
```

Poll every 10–20 seconds until `status` is `completed` or `failed`. A network timeout while polling does not mean generation failed: keep the task ID and resume checking it. Do not create another task to check progress.

### Completed task

```json
{
  "id": "task_...",
  "model": "gemini-omni-1.2-flash",
  "status": "completed",
  "created_at": 1789689600,
  "finished_at": 1789689800,
  "output": {
    "video_url": "https://static.seedrouter.ai/media/tasks/task_example/0.mp4"
  }
}
```

Every video carries Google's invisible SynthID watermark. In our tests 720p clips of 5–8 seconds came back as MP4 (H.264) at 1280 × 720 with a stereo AAC track, 66–86 seconds after submission; an edit of a 3-second clip came back 3 seconds long.

## Errors

Requests rejected before a task is created return an HTTP error with an `error` object and are not charged. A task that fails after acceptance returns HTTP 200 when queried, with `status: "failed"` and an `error` object.

See the [shared error catalog](https://seedrouter.ai/docs/api/errors) for codes, HTTP statuses, and retry guidance.

```json
{
  "id": "task_...",
  "model": "gemini-omni-1.2-flash",
  "status": "failed",
  "error": {
    "code": 60001,
    "message": "The request was rejected by the content policy. Please revise the prompt or input images."
  }
}
```

If submission itself times out, check your tasks before submitting again: the first request may have been accepted.

## Tips

* Describe subject, place, camera move, light and sound; the clip's audio follows the prompt.
* Draft at `360p`, then render the shot you keep at `1080p` or `4k` with the same request.
* For an edit, change one thing at a time and say what must stay the same.
* Add `no text, no logos` to keep invented marks out.

## Related

* [Gemini Omni 1.2 Flash Playground and pricing](https://seedrouter.ai/models/gemini-omni-1-2-flash)
* [Veo 3.1 API reference](https://seedrouter.ai/docs/veo-3-1)
* [Download OpenAPI](https://seedrouter.ai/docs/gemini-omni-1-2-flash.openapi.json)
* [Copyable Markdown](https://seedrouter.ai/docs/gemini-omni-1-2-flash.md)
