Nano Banana Pro API: tutorial en Python, edición y precio
Un POST, un sondeo y una descarga: un script de Nano Banana Pro que funciona.

En esta página
- Respuesta corta
- El id del modelo y lo que necesitas
- El script de Python
- Editar una imagen existente
- 1K, 2K y 4K: qué aporta cada uno
- Errores con los que te vas a topar
- Preguntas frecuentes
- ¿Cuál es el id de modelo de la API de Nano Banana Pro?
- ¿Cuánto cuesta una imagen de Nano Banana Pro?
- ¿Nano Banana Pro puede escribir texto en chino?
- ¿Pido 1K, 2K o 4K?
- ¿Por qué mi edición devolvió 400 invalid_request?
- Fuentes consultadas
- Registro de cambios
Nano Banana Pro es gemini-3-pro-image de Google, y en OmniaKey se llama con un solo POST /v1/media/tasks. Nuestras tres pruebas en 3:4 salieron a 896x1200, 1792x2400 y 3584x4800, y todas las palabras del póster estaban bien escritas.
Respuesta corta
- Modelo:
gemini-3-pro-imagees el id GA de Google. La ficha del modelo en Vertex indica una fecha de lanzamiento del 28 de mayo de 2026. - Llamada: envía
POST https://api.omniakey.com/v1/media/taskscon unaIdempotency-Key, consultaGET /v1/media/tasks/{id}hasta que el estado sea succeeded y descargaassets[0].url. - Parámetros:
parameters.aspect_ratioyparameters.image_size; los valores de tamaño son 1K, 2K y 4K, con la K en mayúscula. - Límite de la petición: 1 MiB para todo el cuerpo, incluidos los datos de imagen en Base64.
- Precio de Google: $0.134 por imagen de 1K/2K y $0.24 por imagen de 4K, según la página de precios de la API Gemini.
- Nuestros tokens: las tres tareas informaron de 1,133, 1,225 y 2,480 tokens de salida. A $120 por millón de tokens de imagen, son $0.136, $0.147 y $0.298.
- Edición: usa
operation: "edit"y pon la imagen de origen eninput.imagecomo{data, mime_type}.
La página del modelo Nano Banana Pro en OmniaKey también acepta gemini-3-pro-image-preview, el id de la instantánea anterior, al mismo precio.
El id del modelo y lo que necesitas
El id que va en tu código es gemini-3-pro-image. La ficha del modelo en Vertex lo lista con etapa de lanzamiento GA y fecha del 28 de mayo de 2026. Admite salida en 1K, 2K y 4K.
El id -preview apunta al mismo modelo. La tabla de modelos de imagen de OmniaKey lo describe como "Same model, -preview snapshot id", con la misma tarifa por llamada.
Necesitas dos cosas:
- Una clave de API de OmniaKey, exportada para que el script la lea:
export OMNIAKEY_API_KEY="your-key". - Python 3. El script de abajo usa solo la biblioteca estándar: urllib, json, time, uuid, base64 y pathlib. No hay que instalar ningún SDK.
El script de Python
Tres pasos: crear la tarea, consultarla y descargar la imagen. Guárdalo como nano_banana.py y ejecútalo con python3 nano_banana.py.
import base64
import json
import os
import time
import urllib.request
import uuid
from pathlib import Path
API = "https://api.omniakey.com/v1/media/tasks"
HEADERS = {
"Authorization": f"Bearer {os.environ['OMNIAKEY_API_KEY']}",
"Content-Type": "application/json",
}
def call(url, payload=None, headers=None, method=None):
body = json.dumps(payload).encode() if payload is not None else None
req = urllib.request.Request(url, data=body, headers=headers or HEADERS, method=method)
with urllib.request.urlopen(req, timeout=60) as resp:
return resp.status, json.loads(resp.read())
def create_task(prompt, aspect_ratio="3:4", image_size="2K", image_path=None):
body = {
"model": "gemini-3-pro-image",
"type": "image",
"operation": "generate" if image_path is None else "edit",
"input": {"prompt": prompt},
"parameters": {"aspect_ratio": aspect_ratio, "image_size": image_size},
}
if image_path:
encoded = base64.b64encode(Path(image_path).read_bytes()).decode("utf-8")
body["input"]["image"] = {"data": encoded, "mime_type": "image/png"}
headers = {**HEADERS, "Idempotency-Key": str(uuid.uuid4())}
status, task = call(API, body, headers, "POST")
print("created", task["id"], "HTTP", status)
return task
def wait(task_id, interval=3, timeout=300):
deadline = time.time() + timeout
while time.time() < deadline:
_, task = call(f"{API}/{task_id}")
print(task["status"], task["progress"]["percent"])
if task["status"] in ("succeeded", "failed", "canceled"):
return task
time.sleep(interval)
# A timeout is not a failure: keep the task id and poll it again.
raise TimeoutError(f"task {task_id} is still running")
def download(task, out_path):
asset = task["assets"][0]
with urllib.request.urlopen(asset["url"], timeout=120) as resp:
Path(out_path).write_bytes(resp.read())
print("saved", out_path, asset["mime_type"], asset["byte_size"], "bytes")
if __name__ == "__main__":
task = create_task(
"A vintage travel poster for the Night Train from Zürich to Milano, "
"departing 21:40 from platform 7. A steam train crosses a stone arch "
"bridge below snowy mountains under a deep blue night sky, with a cream "
"border. Spell every word exactly as written.",
aspect_ratio="3:4",
image_size="2K",
)
task = wait(task["id"])
if task["status"] != "succeeded":
raise SystemExit(f"{task['status']}: {task.get('error')}")
download(task, "night-train.jpg")
image_size acepta 1K, 2K o 4K. La guía de imágenes de Google lo dice claro: "You must use an uppercase 'K' … Lowercase parameters (e.g., 1k) will be rejected." Envía 2K, no 2k.
Idempotency-Key es obligatoria. Generar un UUID nuevo en cada petición es la regla sencilla; reutiliza una clave solo cuando reintentes exactamente el mismo cuerpo. OmniaKey devuelve la tarea original con HTTP 200 en lugar de cobrarte dos veces, y responde 409 si la misma clave llega con un cuerpo distinto.
La llamada de creación devuelve 202 con un id. La documentación de tareas multimedia de OmniaKey describe todo el ciclo; la tarea terminada trae estos campos:
{
"id": "task_AbMRVqzSnVh0VwBj0S7NuMUxy5sZtfHP",
"status": "succeeded",
"progress": {"percent": 100, "stage": "completed"},
"usage": {"total_tokens": 1133},
"assets": [
{
"kind": "image",
"mime_type": "…",
"url": "https://…signed-url…"
}
]
}
Lee assets[0].url y descárgala en ese momento: el enlace firmado dura alrededor de una hora y el registro de la tarea se guarda 24 horas. El campo mime_type te dice el formato; los modelos Gemini suelen devolver JPEG.
El mismo script en 1:1 y 2K, con un cartel en chino como prompt, devolvió esto:

Editar una imagen existente
Pon operation: "edit" y pasa la imagen de origen en input.image como {data, mime_type}. El script de arriba ya lo hace cuando le das un image_path:
task = create_task(
"Hang this poster in a thin black frame on a warm white wall, with a brass "
"picture light above it, a low wooden cabinet below and a trailing plant on "
"the right. Keep the poster exactly as it is.",
aspect_ratio="1:1",
image_size="2K",
image_path="night-train-2k.png",
)
El cuerpo que envía tiene este aspecto:
{
"model": "gemini-3-pro-image",
"type": "image",
"operation": "edit",
"input": {
"prompt": "Hang this poster in a thin black frame on a warm white wall…",
"image": {"data": "…base64…", "mime_type": "image/png"}
},
"parameters": {"aspect_ratio": "1:1", "image_size": "2K"}
}
La imagen de origen del ejemplo es un PNG, así que el script la etiqueta image/png; cambia esa etiqueta para un JPEG. Para varias referencias, usa input.images y da a cada entrada la misma forma {data, mime_type}. La guía de Google pone el límite en 14 imágenes de referencia; para gemini-3-pro-image el reparto es 6 imágenes de objeto, 5 de personaje y 3 de estilo.
Mantén el cuerpo por debajo de 1 MiB. Base64 aumenta el archivo alrededor de un tercio, así que reduce o comprime el origen antes de codificarlo. Nuestra edición usó el póster de 2K y conservó cada palabra y la maquetación:

1K, 2K y 4K: qué aporta cada uno
Ejecutamos el mismo prompt del póster en 3:4 con los tres tamaños. Los píxeles coincidieron exactamente con la tabla de Google para 3:4: 896x1200 en 1K, 1792x2400 en 2K y 3584x4800 en 4K. El texto del póster fue correcto en los tres tamaños.



Lo que cambia con el tamaño es el detalle, no la ortografía:
- 1K: el frontal del tren está apretado: lámparas, ruedas y bielas quedan muy juntas.
- 2K: el pueblo y sus dos agujas aparecen en la ladera derecha, la chimenea suelta un hilo claro de humo y el puente muestra siete arcos.
- 4K: los tres vagones y el ténder se separan, y la sillería muestra juntas de distinto grosor. La maquinaria bajo la locomotora sigue simplificada.
La velocidad subió con el tamaño: 28.4 s, 48.2 s y 66.9 s. Cada tamaño se ejecutó una vez, así que lee esos segundos como una sola pasada.
Google cobra la salida de imagen a $120 por millón de tokens, y su tabla da 1,120 tokens tanto para 1K como para 2K y 2,000 tokens para 4K. De ahí sale su propia estimación:
1,120 × $120 ÷ 1,000,000 = $0.134 per 1K image
1,120 × $120 ÷ 1,000,000 = $0.134 per 2K image
2,000 × $120 ÷ 1,000,000 = $0.24 per 4K image
Nuestras tareas informaron de más tokens que los ejemplos de Google. Aquí está la misma aritmética con nuestros números:
1,133 × $120 ÷ 1,000,000 = $0.136 per 1K image
1,225 × $120 ÷ 1,000,000 = $0.147 per 2K image
2,480 × $120 ÷ 1,000,000 = $0.298 per 4K image
| Tamaño | Píxeles, 3:4 | Nuestro tiempo | Nuestros tokens | Estimación de Google |
|---|---|---|---|---|
| 1K | 896x1200 | 28.4 s | 1,133 | $0.134 |
| 2K | 1792x2400 | 48.2 s | 1,225 | $0.134 |
| 4K | 3584x4800 | 66.9 s | 2,480 | $0.24 |
OmniaKey cobra la llamada de imagen a tarifa plana, no por token, así que su importe no se mueve con esos recuentos; la página del modelo tiene la tarifa actual por llamada, y una tarea fallida se reembolsa. La estimación de Google por tarifa de tokens para las mismas tres imágenes es $0.134, $0.134 y $0.24.
Errores con los que te vas a topar
Las fallas de aquí se reducen casi siempre a un nombre de campo o a un tamaño de archivo, no al modelo. Estas son las que la documentación multimedia de OmniaKey lista para este endpoint:
| HTTP | Código o estado | Qué significa | Qué hacer |
|---|---|---|---|
| 400 | invalid_request | Cuerpo mal formado, operación no admitida o parámetro incorrecto | Revisa el JSON y los nombres de campo de abajo |
| 503 | no_available_channel | Ningún canal atiende este modelo ahora | Cambia de modelo; reintentar no lo arregla |
| — | failed | La tarea terminó sin resultado | Lee error.code y error.message |
Una tarea fallida no es un error HTTP: la llamada de creación salió bien, así que consulta la tarea y lee su objeto error. Las tareas fallidas y canceladas se reembolsan de forma automática.
Un origen a resolución completa enviado en Base64 puede empujar el cuerpo por encima de 1 MiB. Redúcelo primero y mira la longitud codificada, no solo el tamaño del archivo.
La guía de Google rechaza un 1k en minúscula. Usa 1K, 2K o 4K.
La documentación de imagen de OmniaKey también rechaza size y un mime_type de primer nivel en los modelos Gemini, porque no son parámetros de Gemini. Usa parameters.aspect_ratio y parameters.image_size, y lee el formato de salida en el campo mime_type de la respuesta.
Preguntas frecuentes
¿Cuál es el id de modelo de la API de Nano Banana Pro?
gemini-3-pro-image. La ficha de Vertex de Google lo marca como GA con fecha de lanzamiento del 28 de mayo de 2026, y OmniaKey acepta el mismo id. El id anterior gemini-3-pro-image-preview sigue funcionando en OmniaKey y apunta al mismo modelo.
¿Cuánto cuesta una imagen de Nano Banana Pro?
Google estima $0.134 para una imagen de 1K o 2K y $0.24 para una de 4K, con su tarifa de $120 por millón de tokens de imagen. Nuestras tareas informaron de 1,133, 1,225 y 2,480 tokens, que a esa tarifa son $0.136, $0.147 y $0.298. La página del modelo en OmniaKey lista su propia tarifa por llamada.
¿Nano Banana Pro puede escribir texto en chino?
Sí. Nuestro cartel de 2K volvió con tres líneas correctas en chino — 同福客栈, 住宿 餐饮 茶水 y 010-6789 4321 — con los 11 dígitos y el guion.
¿Pido 1K, 2K o 4K?
Para un póster como el nuestro, 2K es el punto medio útil. Los tres tamaños escribieron bien el póster, así que 4K compra detalle más fino — vagones separados y juntas de ladrillo — en vez de mejor texto. Usa 1K para borradores en los que 896x1200 sea suficiente.
¿Por qué mi edición devolvió 400 invalid_request?
Las causas habituales son un cuerpo de más de 1 MiB, el origen en el campo equivocado o un modelo Gemini que recibe size o un mime_type de primer nivel. Pon la imagen en input.image como {data, mime_type}, mantén el cuerpo codificado por debajo de 1 MiB y usa aspect_ratio y image_size.
Fuentes consultadas
- Google Cloud: ficha del modelo Gemini 3 Pro Image — consultada el 3 nov 2026.
- Google: guía de generación de imágenes de la API Gemini — consultada el 3 nov 2026.
- Google: precios de la API Gemini — consultada el 3 nov 2026.
- Google: anuncio de Nano Banana Pro — consultado el 3 nov 2026.
Registro de cambios
- 2026-11-03: primera versión; cinco llamadas de prueba hechas ese día a través de OmniaKey.
Modelos de este artículo
Artículos relacionados
Nano Banana 2.1: acceso API, precios y migración
Compara Nano Banana 2.1 con Nano Banana 2 y crea tareas de imagen compatibles directamente en OmniaKey.
Fotos de producto con Nano Banana: 8 prompts probados
Ocho prompts, 22 ediciones y dos modelos: qué tomas conservaron la etiqueta, dónde se reflejó el zapato y qué modelo elegir para cada trabajo.
Seedream 5.0 Pro vs Nano Banana Pro: mismos prompts, precio y velocidad
Cinco prompts iguales, dos modelos, tiempos medidos y el precio por imagen 2K.
