HiAPI
Blog

Tutorial

Cómo usar nano-banana-pro a través de la API de HiAPI: ejemplos con curl y Python

Oct 31, 2026
平面流体形态层叠交错的封面图,墨色底上流动着青瓷绿与石板灰的波纹,呼应教程主题。

Qué te ofrece nano-banana-pro en HiAPI

nano-banana-pro es un modelo de generación de imágenes al que puedes llamar a través de la API unificada de HiAPI. En lugar de integrarte directamente con el proveedor del modelo, solo tienes que enviar a HiAPI una solicitud con el formato unificado para obtener la imagen generada: la misma autenticación, las mismas convenciones de endpoint y el mismo envoltorio de respuesta que con los modelos de otras plataformas.

nano-banana-pro está diseñado para la generación de imágenes guiada por prompts y permite adjuntar imágenes de referencia además del prompt de texto. Las imágenes de referencia te permiten guiar la salida con contexto visual (sujeto, estilo, composición) en lugar de describirlo todo con palabras. La salida se entrega en resolución 2K, por lo que el modelo es más adecuado para activos de producción que para bocetos rápidos.

Al terminar este tutorial tendrás una integración completa y funcional que puede:

  • enviar un prompt a nano-banana-pro a través de HiAPI con una solicitud curl verificada;
  • reproducir la misma llamada en Python sin cambiar el payload de la solicitud;
  • adjuntar una imagen de referencia a la solicitud;
  • enviar tareas asíncronas, consultar su estado hasta que terminen y gestionar los reintentos de forma razonable;
  • descargar la imagen 2K terminada y almacenarla en tu propia infraestructura.

Cada sección se apoya en la anterior, así que el camino más seguro es avanzar en orden: primero confirma la solicitud a mano y después llévala al código.

Antes de enviar la primera solicitud

Necesitas tres cosas antes de la primera llamada.

Una clave de API

Crea una clave de API en tu cuenta de HiAPI y asegúrate de que no quede incluida en el control de versiones. Trátala como cualquier otro secreto: cárgala desde una variable de entorno (HIAPI_API_KEY) o desde un gestor de secretos y nunca la codifiques directamente en archivos que puedas llegar a confirmar. Si la clave se filtra, rótala en el panel de control en lugar de intentar borrarla del historial.

Un cliente HTTP

Cualquier herramienta capaz de enviar solicitudes HTTPS sirve. Para la primera solicitud, curl en la línea de comandos es ideal porque no hay ningún framework entre tú y la red: cada cabecera y cada byte del cuerpo de la respuesta son visibles. Para la parte de Python, la biblioteca estándar urllib.request es suficiente; si ya usas requests o httpx, la correspondencia es la misma. Este tutorial limita Python a la biblioteca estándar, así que no necesitas instalar nada adicional.

Un lugar donde guardar la salida

Como las tareas de nano-banana-pro son asíncronas, planifica desde el principio el directorio o el bucket donde guardarás las imágenes terminadas. Para desarrollo basta una carpeta local output/; en producción, el destino debería ser el almacenamiento de objetos.

No necesitas instalar el SDK del proveedor. HiAPI funciona mediante llamadas HTTPS normales, así que la solicitud que construyes en curl es idéntica a la que enviará después tu cliente de Python.

Una solicitud curl funcional, explicada paso a paso

La forma más rápida de confirmar que la clave, el endpoint y el payload son correctos es enviar una solicitud a mano. Antes de escribirla, desglósala en sus partes.

Endpoint y método

Todas las llamadas a modelos se envían a la misma URL base de HiAPI, y el modelo se identifica en el cuerpo de la solicitud, no en la ruta. Las solicitudes de generación usan POST.

Cabeceras

Hay tres cabeceras importantes en cada llamada:

  • Authorization: Bearer $HIAPI_API_KEY: tu clave, enviada como token bearer.
  • Content-Type: application/json: para solicitudes que solo contienen un prompt.
  • Accept: application/json: para recibir una respuesta estructurada en lugar de una página de error HTML.

Cuerpo de la solicitud

El cuerpo JSON transporta el nombre del modelo y los parámetros de generación. Como mínimo, debes enviar el identificador del modelo y tu prompt:

curl -sS -X POST "$HIAPI_BASE_URL" \
  -H "Authorization: Bearer $HIAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "model": "nano-banana-pro",
    "input": {
      "prompt": "a glass terrarium on a sunlit windowsill, soft morning light, shallow depth of field"
    }
  }'

Antes de ejecutar este comando, define HIAPI_BASE_URL y HIAPI_API_KEY en tu shell. Guardar la URL en una variable significa que más adelante podrás apuntar el mismo script a una URL de staging o de sandbox sin modificar el comando.

Leer la respuesta

Un envío correcto devuelve un objeto JSON que identifica la tarea. El campo importante es el identificador de la tarea: lo usarás en el paso de consulta de estado. Como la generación tarda, no esperes obtener la imagen en la primera respuesta; nano-banana-pro funciona de forma asíncrona y esta llamada es solo la parte de envío de la interacción.

Si el comando devuelve un error, detente aquí y corrígelo antes de escribir código. La solicitud curl verificada es tu implementación de referencia: cada paso posterior debe producir la misma solicitud HTTP.

Llevar la solicitud a Python

La migración es mecánica: la URL, el método, las cabeceras y el cuerpo JSON permanecen igual. Solo cambia el cliente.

La misma solicitud con urllib

import json
import os
import urllib.request

api_key = os.environ["HIAPI_API_KEY"]
base_url = os.environ["HIAPI_BASE_URL"]

payload = {
    "model": "nano-banana-pro",
    "input": {
        "prompt": "a glass terrarium on a sunlit windowsill, soft morning light, shallow depth of field"
    },
}

request = urllib.request.Request(
    base_url,
    data=json.dumps(payload).encode("utf-8"),
    method="POST",
    headers={
        "Authorization": f"Bearer {api_key}",
        "Content-Type": "application/json",
        "Accept": "application/json",
    },
)

with urllib.request.urlopen(request, timeout=60) as response:
    body = json.loads(response.read().decode("utf-8"))

print(body)

Reglas de correspondencia

Al convertir desde curl, hay tres detalles que suelen causar errores:

  1. El cuerpo debe ser bytes. json.dumps genera una cadena; hay que codificarla antes de pasarla al objeto de solicitud.
  2. Las cabeceras son un diccionario, no flags. Cada línea -H se convierte en un par clave/valor. Conserva el prefijo Bearer y el espacio que le sigue.
  3. El método debe especificarse explícitamente. Cuando hay datos, urllib.request usa POST de forma predeterminada, pero establecer method="POST" hace explícita la intención y evita sorpresas si más adelante eliminas el cuerpo de la solicitud.

Si usas requests, la forma equivalente es requests.post(base_url, headers=headers, json=payload, timeout=60): json= se encarga de la serialización y del tipo de contenido por ti. Si usas httpx, la forma de la llamada es la misma.

Una pequeña función auxiliar que vale la pena tener

Coloca la llamada de envío dentro de una función que reciba el prompt y devuelva el identificador de la tarea. Cada sección posterior (imágenes de referencia, consulta de estado, descarga) se apoya en esa función, y mantenerla en un solo lugar significa que los cambios en la forma de la solicitud ocurren una sola vez.

Enviar imágenes de referencia junto con el prompt

Las imágenes de referencia cambian la forma de la solicitud, así que decide cuanto antes qué tipo de entrada usará tu aplicación.

Dos opciones prácticas

Entrada basada en URL. Si la imagen de referencia ya es accesible por HTTPS, puedes adjuntar su URL junto con el prompt en el cuerpo de la solicitud. Esto mantiene la solicitud como application/json, la forma más fácil de reintentar y registrar.

Subir un archivo. Si la imagen está en el cliente o en almacenamiento privado, puedes enviarla como parte de archivo en una solicitud multipart/form-data. En ese caso, la cabecera Content-Type: application/json se sustituye por el tipo de contenido multipart (deja que tu cliente HTTP lo genere para asegurar que el boundary sea correcto) y los campos JSON pasan a ser campos de formulario dentro de la misma solicitud.

Para la mayoría de las integraciones del lado del servidor, la entrada basada en URL es más sencilla: tus imágenes ya están en el almacenamiento de objetos, la solicitud sigue siendo JSON y evitas enviar dos veces cuerpos de solicitud grandes al reintentar.

Mantener sincronizados el prompt y la imagen de referencia

El prompt debe describir para qué sirve la imagen de referencia, no solo qué contiene. «Iguala la iluminación y los tonos de la imagen de referencia; cambia el sujeto por un jarrón de cerámica» le da al modelo una tarea clara. Un prompt que ignora la imagen de referencia desperdicia la entrada.

Validar antes de enviar

Las imágenes de referencia son la causa más común de errores en las solicitudes. Comprueba que la URL sea accesible públicamente (o que ambos extremos de tu sistema hayan acordado la caducidad de la URL firmada), que el tipo de archivo sea aceptado por el modelo y que la imagen no sea tan grande como para provocar un tiempo de espera agotado en la subida. Haz estas comprobaciones primero en tu propio código: depurar una validación del cliente fallida cuesta mucho menos que una solicitud rechazada.

Gestionar tareas asíncronas y consultar los resultados

La generación con nano-banana-pro es asíncrona. Estructura tu cliente en torno a tres pasos independientes: enviar, consultar el estado y descargar. Mezclarlos en una sola función dificulta razonar sobre reintentos y tiempos de espera.

Paso 1: enviar

Envía la solicitud anterior y guarda el identificador de tarea que devuelve. Persiste ese identificador en algún lugar duradero (una fila de base de datos o un mensaje de cola), porque tu proceso puede reiniciarse entre el envío y la finalización.

Paso 2: consultar el estado

Usa la misma URL base y la misma cabecera Authorization, incluyendo el identificador de la tarea en la solicitud, para obtener el estado de la tarea. Consulta a intervalos en lugar de hacer un bucle ajustado; unos segundos entre comprobaciones es lo habitual, y si varias comprobaciones consecutivas devuelven un estado pendiente, conviene aplicar un retroceso exponencial.

import time

TERMINAL = {"succeeded", "failed"}

def wait_for_job(job_id, timeout=300, interval=3):
    deadline = time.monotonic() + timeout
    while time.monotonic() < deadline:
        status = get_job_status(job_id)  # same headers as submit
        if status in TERMINAL:
            return status
        time.sleep(interval)
    raise TimeoutError(f"job {job_id} did not finish in time")

Paso 3: respetar los estados

Trata el campo de estado como una enumeración. Una tarea está en ejecución, ha terminado correctamente o ha fallado. Gestiona explícitamente los tres casos: si tiene éxito, pasa a la descarga; si falla, lee el mensaje de error y determina si el problema está en la entrada o en el prompt; si se agota el tiempo, deja de consultar y expón el identificador de la tarea para investigarlo más adelante.

Los reintentos pertenecen a dos niveles

Los reintentos a nivel de red deben aplicarse a la llamada de envío y a cada solicitud de consulta de estado, con un número limitado de intentos. Los reintentos a nivel de tarea son distintos: si una tarea falla por un prompt o una imagen de referencia deficientes, volver a enviar el mismo payload fallará de la misma manera. Reintenta la tarea en sí solo después de cambiar la entrada.

Un patrón de producción habitual es que un worker se encargue del bucle de consulta de estado, de modo que las solicitudes web nunca se bloqueen esperando la generación. Envía desde tu manejador de API, entrega el identificador de la tarea al worker y notifica al cliente cuando el worker termine.

Descargar y almacenar la salida en 2K

La respuesta final de la tarea apunta a la imagen generada en lugar de incluirla, lo que significa que la descarga es un paso del que tú eres responsable.

Obtener la imagen

Cuando la tarea informa de éxito, la respuesta contiene la ubicación de la salida. Recupérala con una solicitud GET normal y luego escribe los bytes en un archivo o transmítelos en streaming al almacenamiento. Durante el desarrollo, guarda en un directorio local con un nombre predecible construido a partir del identificador de la tarea, para poder asociar el archivo con el registro de la tarea.

import pathlib
import urllib.request

def save_image(url, job_id, out_dir="output"):
    pathlib.Path(out_dir).mkdir(exist_ok=True)
    target = pathlib.Path(out_dir) / f"nano-banana-pro-{job_id}.png"
    with urllib.request.urlopen(url, timeout=60) as response:
        target.write_bytes(response.read())
    return target

Almacenar correctamente

En producción, transmite la respuesta directamente en streaming al almacenamiento de objetos en lugar de escribirla en el disco local, de modo que el comportamiento sea el mismo independientemente del worker que procese la tarea. Registra la clave del objeto y el identificador de la tarea en la base de datos, y comprueba que el tipo de contenido y la extensión del archivo coincidan con lo que genera el modelo. Si la imagen se va a servir en una página web, genera las miniaturas en el mismo proceso para que las páginas públicas nunca carguen el archivo completo en resolución 2K.

Planificar la política de retención

La salida generada son tus datos. Decide cuánto tiempo conservarla, si necesitas control de versiones y si el destino final es algo que tu aplicación puede regenerar si se pierde. Si la respuesta es negativa, guarda también el payload de la solicitud junto con la imagen, para que un futuro bug o un cambio de modelo nunca te impida reproducir el resultado.

Puntos de fallo habituales y cómo depurarlos

La mayoría de las primeras integraciones fallan por unas pocas causas. Antes de suponer que el modelo tiene un problema, revisa esta lista punto por punto.

  • Errores de autorización. Falta el prefijo Bearer , la clave tiene un salto de línea final por haberse copiado de un archivo de entorno, o la clave que usas pertenece a un entorno distinto del de la URL base configurada.
  • Tipos de contenido que no coinciden. Enviar campos JSON con una cabecera multipart, o enviar un archivo con application/json, es la causa más común de que se rechacen las solicitudes con imagen de referencia. Para los cuerpos multipart, deja que el cliente configure la cabecera.
  • Método o forma del cuerpo incorrectos. Usar GET en lugar de POST, o usar un prompt de nivel superior en lugar del objeto anidado input, produce errores de validación que parecen totalmente ajenos. Compara tu solicitud byte a byte con la llamada curl verificada; curl -v muestra las cabeceras que realmente se envían.
  • Consultar demasiado rápido o no consultar nunca. Solicitar el estado con demasiada frecuencia provoca limitación de tasa; no consultar nunca no devuelve nada. Usa un intervalo fijo con retroceso y un tiempo de espera máximo.
  • URL de salida caducada. Si esperas demasiado entre la finalización de la tarea y la descarga, la URL de salida firmada puede caducar. Descarga inmediatamente después del éxito o prepara una ruta de recuperación que obtenga una nueva ubicación.
  • Fallos silenciosos en el código. Registra siempre el código de estado HTTP y el cuerpo de la respuesta cuando haya un error. El mensaje genérico de excepción que lanza el cliente HTTP oculta la parte útil de la respuesta.

Cuando algo no esté claro, vuelve a la solicitud curl verificada de la primera sección. Si esa solicitud funciona y tu llamada en Python no, la diferencia entre ambas es el bug.

Artículos relacionados

Ver todos los artículos →

Empieza a crear con artefactos de IA persistentes

Consigue tu API key y llama a modelos de imagen, vídeo y audio a través de una única API basada en tasks.

Leer la documentación de la API