> ## 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.

# Generación de vídeo Gemini Omni 1.2 Flash

> Vídeos desde texto o imágenes, referencias de sujetos, interpolación de fotogramas inicial/final, edición y extensión. Hasta 4K, 24fps, con audio.

> [!NOTE]
>
> La generación desde texto o imágenes admite segundos enteros de 3 a 15, con 10 por defecto. La interpolación inicial/final y el segmento añadido en la extensión admiten hasta 10 segundos. La edición ignora `duration` y mantiene la duración del vídeo original. La entrada de vídeo activa la edición por defecto; para extender se requiere `"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"
    }
  ]
}
```

## Autenticación

**Authorization** `string` *required*

Usa autenticación Bearer Token. Obtén una clave en la [gestión de claves API](https://apimart.ai/keys) y envía las solicitudes con `Content-Type: application/json`.

## Parámetros de solicitud

**model** `string` *required*

Debe ser `gemini-omni-1.2-flash`.

**prompt** `string` *required*

Instrucciones de texto obligatorias: describe la escena para texto a vídeo, o el movimiento, estilo y cambios para los otros modos. `prompt` es obligatorio incluso al proporcionar imágenes de referencia, fotogramas inicial/final, vídeo o `extend_from_task_id`. Omitirlo devuelve HTTP 400.

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

Duración de salida para la generación desde texto o imágenes, entero entre `3` y `15`, con `10` por defecto. La interpolación inicial/final y la extensión solo admiten `3`–`10` segundos. En la extensión indica la duración del segmento añadido; el vídeo devuelto incluye el original y el nuevo segmento. La edición ignora `duration` y mantiene la duración del vídeo original. Los valores del parámetro fuera del rango hacen fallar la tarea con `invalid_duration`.

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

`360p` / `720p` / `1080p` / `4k`, sin distinguir mayúsculas; `2160p` equivale a `4k`. `1080p` y `4k` se obtienen mediante reescalado. La resolución afecta a los tokens de salida y al saldo reservado. Otros valores hacen fallar la tarea con `invalid_resolution`.

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

Solo `16:9` (horizontal, por defecto) y `9:16` (vertical). Otros valores se tratan como `16:9`.

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

Imágenes de referencia solo mediante URL HTTP(S) directas y accesibles públicamente. No se admiten Data URL ni Base64. Una imagen se usa como inicio; varias sirven como referencias de sujetos. Máximo 10 imágenes, incluidos los fotogramas inicial/final. Para personajes, se recomiendan como máximo 2 personajes con hasta 3 imágenes cada uno, sin superar 6 imágenes en total.

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

Fotograma inicial. Por sí solo define el inicio; junto con `last_frame_image` activa la interpolación entre ambos fotogramas. Solo se admiten URL HTTP(S) directas de imagen y accesibles públicamente.

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

Fotograma final; requiere `first_frame_image`, de lo contrario la tarea falla con `invalid_frame_images`. Ambas imágenes deben tener la misma proporción y coincidir con `aspect_ratio`. Solo se admiten URL HTTP(S) directas de imagen y accesibles públicamente.

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

Imágenes con roles, equivalentes a los campos directos de fotograma inicial/final. Elige una sola forma de especificarlos. Todas las imágenes usadas cuentan para el límite total de 10.

**Elemento del array**

**url** `string` *required*

Solo se admiten URL HTTP(S) directas de imagen y accesibles públicamente.

**role** `string` *required*

`first_frame` es el fotograma inicial y `last_frame` el final. Los demás roles se tratan como referencias. El fotograma final necesita uno inicial.

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

Vídeo para editar o extender: como máximo 1 clip de hasta 15 segundos. Solo se admiten URL HTTP(S) directas de vídeo y accesibles públicamente. No se admiten Data URL ni Base64. Por defecto se realiza una edición.

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

Tipo de tarea: `auto` (por defecto, deducido de las entradas) / `edit` (edición) / `extend` (extensión) / `reference` (varias imágenes de referencia). También acepta `text_to_video` / `image_to_video` / `reference_to_video`. Si se omite o se establece en `auto`, `video_urls` y `extend_from_task_id` editan por defecto. Para extender, indica `extend` de forma explícita.

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

ID de una tarea de generación anterior propia para reutilizar el vídeo sin volver a subirlo. Por defecto se edita. Con `"omni_reference_task_type": "extend"` se añade al final un segmento de hasta 10 segundos.

## Funciones y límites

* La salida tiene 24fps e incluye diálogos, música o efectos de sonido. Describe el audio deseado en `prompt`.
* No se admiten audio de entrada, system prompt, `temperature` ni parámetros de prompt negativo. Escribe las exclusiones directamente en `prompt`.
* Restricciones regionales del proveedor: en el EEE, Suiza y Reino Unido no se admite editar o extender vídeos subidos, ni editar imágenes que contengan menores.
* Todas las salidas incluyen una marca de agua invisible SynthID.

## Ejemplos

Envía cada cuerpo JSON a `POST /v1/videos/generations`. Sustituye las URL y los ID de ejemplo por tus propios recursos disponibles.

### Vídeo vertical 4K de 15 segundos

```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
}
```

### Imagen a vídeo y referencias de sujetos

```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
}
```

### Interpolación de fotogramas inicial y final

```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
}
```

### Definir fotogramas mediante 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
}
```

### Edición de vídeo

```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"
  ]
}
```

La edición mantiene la duración del vídeo original; `duration` no tiene efecto.

Usa instrucciones de edición breves y concretas. Para un cambio local puedes añadir `Keep everything else the same`.

### Extender una tarea existente

```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
}
```

Para extender un vídeo subido, sustituye `extend_from_task_id` por `video_urls` y conserva `"omni_reference_task_type": "extend"`. El vídeo devuelto contiene el original seguido del segmento añadido. `duration` controla solo la duración añadida, de hasta 10 segundos; solo se cobran los segundos añadidos. Por ejemplo, un vídeo original de 5 segundos con `duration: 4` devuelve un vídeo de unos 9 segundos.

## Respuesta de envío y consulta de tareas

Un envío correcto devuelve HTTP 200; lee `data[0].task_id`. Consulta el [estado de la tarea](https://docs.apimart.ai/es/api-reference/tasks/status.md) cada 5–10 segundos hasta `completed` o `failed`. Se recomienda un tiempo total de espera de 10 minutos. Si el cliente agota el tiempo, sigue consultando la tarea original sin enviarla de nuevo.

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

Tiempos orientativos: un vídeo de 15 segundos a 360p tarda unos 30 segundos; a 4K, unos 5 minutos. Comprueba siempre el estado de la tarea.

```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` en la respuesta de consulta es el objeto de tarea. `data.result.videos[0].url` es un array; la primera URL es `data.result.videos[0].url[0]`. Se puede descargar o reproducir directamente. Guarda una copia para conservarla a largo plazo. `data.cost` es el cargo final en USD.

| Estado | Acción |
| - | - |
| `pending` / `processing` | Sigue consultando; el progreso está en `data.progress`. |
| `completed` | Lee la URL y guarda el vídeo. |
| `failed` | Lee `data.error.message`. Las tareas fallidas no se cobran. |

## Facturación y saldo reservado

Se factura por tokens: la resolución afecta a los tokens de vídeo por segundo. En la generación desde texto o imágenes, `duration` define la duración de salida. La edición ignora el parámetro y mantiene la duración del vídeo original; la extensión lo usa solo para el segmento añadido. Consulta los [precios de APIMart](https://apimart.ai/pricing).

Al enviar, se reserva saldo según la resolución y `max(10, duration)` segundos; con vídeo de entrada se estiman 15 segundos. La reserva no es el cargo final. Tras completarse, se ajusta al uso real; el importe final figura en `data.cost`.

La extensión se cobra solo por los segundos añadidos. Los fallos no se cobran. Si el saldo no cubre la reserva, se devuelve HTTP 402.

## Gestión de errores

Los errores de parámetros (`invalid_*` / `unsupported_*`) cambian la tarea inmediatamente a `failed`, sin cargo. Comprueba el estado incluso después de un envío correcto.

| Error / estado | Causa y solución |
| - | - |
| `invalid_duration` | `duration` fuera de 3–15, o interpolación / extensión de más de 10 segundos. Usa un entero dentro del rango. |
| `invalid_task_type` | Valor de `omni_reference_task_type` no admitido. Usa `auto` / `edit` / `extend` / `reference`; también se aceptan `text_to_video` / `image_to_video` / `reference_to_video`. |
| `invalid_resolution` | Usa `360p` / `720p` / `1080p` / `4k`; también se acepta `2160p`. |
| `invalid_frame_images` | Solo se proporcionó el fotograma final. Añade el inicial. |
| `unsupported_image_count` | Más de 10 imágenes, incluidos los fotogramas inicial/final. Reduce la cantidad. |
| `unsupported_video_count` | Más de 1 vídeo de entrada. Usa un solo clip de hasta 15 segundos. |
| `HTTP 400` | Falta el parámetro obligatorio `prompt`. Envía instrucciones de texto incluso al proporcionar contenido multimedia. |
| `HTTP 401` | Clave no válida. Comprueba Authorization. |
| `HTTP 402` | Saldo insuficiente para la reserva. Recarga o reduce la resolución. |
| `HTTP 429` | Límite de solicitudes alcanzado. Reintenta con espera progresiva. |
| `status: failed` | Fallo del proveedor o rechazo por políticas de contenido. Lee `data.error.message` y ajusta la solicitud. |

## Preguntas frecuentes

### ¿Es obligatorio `prompt` si proporciono imágenes o vídeo?

Sí. Todos los modos requieren `prompt`, incluidos la generación desde imágenes, la interpolación inicial/final, la edición, la extensión y la reutilización de vídeo mediante `extend_from_task_id`. Omitir este campo devuelve HTTP 400.

### ¿Puedo enviar imágenes o vídeo directamente en Base64?

No. `image_urls`, `first_frame_image`, `last_frame_image`, `image_with_roles[].url` y `video_urls` solo aceptan URL HTTP(S) directas y accesibles públicamente. No envíes `data:image/...`, `data:video/...` ni cadenas Base64 sin prefijo.


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