Documentación

Documentación

Generación de imágenes

Hay dos endpoints: de texto a imagen y de edición/imagen a imagen. Las URL de resultados que devuelven ambos son permanentes: Kunavo archiva cada imagen en su propia CDN.

Kunavo ofrece /v1/images/generations (de texto a imagen) y /v1/images/edits (de imagen a imagen/edición). Ambos son sincrónicos de forma predeterminada: la llamada se bloquea hasta que finaliza el proveedor ascendente y luego devuelve las URL de los resultados. También puede usar el modo asíncrono con "async": true o con un webhook_url.

De texto a imagen

Endpoint: POST /v1/images/generations. Use el método images.generate del SDK de OpenAI o invoque directamente con curl.

img = client.images.generate(
    model="nano-banana-pro",
    prompt="a red origami crane on a white desk, soft window light",
    size="1024x1024",
)
print(img.data[0].url)

Parámetros comunes

ParámetroTipoNotas
modelstringCualquier slug de modelo de imagen de /v1/models.
promptstringInstrucción de texto. Siempre es obligatoria.
sizestringFormato de OpenAI, como "1024x1024". Se transforma en una relación de aspecto del proveedor ascendente.
qualitystandard|hdCuando sea compatible (gpt-image).
resolution1K|2K|4KNivel de resolución para modelos con niveles; consulte más abajo Resolution tiers. Se factura según el nivel.
nintNúmero de imágenes. La mayoría de los modelos siempre devuelven 1.
inputobjectMecanismo alternativo; consulte más abajo Raw input.
Las URL de resultados son enlaces permanentes a files.kunavo.com: Kunavo archiva cada imagen en su propia CDN, así que, a diferencia de las URL directas del proveedor, nunca caducan. Si una imagen no se puede archivar, su URL es la URL temporal del proveedor, en otro host: descargue esa imagen y vuelva a alojarla.

Niveles de resolución

Varios modelos de imagen cobran un precio escalonado según la resolución de salida. Pase resolution para elegir un nivel; si lo omite, se usa el nivel predeterminado. Se le factura el nivel que se haya generado realmente.

Modelo (y su variante -edit)Niveles: precio de cada unoPredeterminado
nano-banana-21K $0.0469 · 2K $0.0707 · 4K $0.10571K
nano-banana-pro1K / 2K $0.067 · 4K $0.122K
gpt-image-21K / 2K / 4K — $0.0633 (precio fijo)1K

La familia veo-3 también tiene niveles según la resolución: los precios de cada nivel figuran en la página /models de cada modelo.

GPT-Image-2 no puede generar imágenes 4K con una relación de aspecto 1:1 (cuadrada). Si solicita resolution = 4K con un tamaño cuadrado, la llamada se reducirá automáticamente a 2K, que será el nivel facturado.

Edición de imagen/imagen a imagen

Endpoint: POST /v1/images/edits. Pase la imagen de origen como URL (HTTPS o data: base64) mediante image para ediciones de una sola imagen o mediante image_urls para referencias con varias imágenes.

# Image edit / image-to-image: pass the source image URL
import requests

resp = requests.post(
    "https://api.kunavo.com/v1/images/edits",
    headers={"Authorization": f"Bearer {API_KEY}"},
    json={
        "model": "gpt-image-2-edit",
        "prompt": "recolor the crane to bright blue, keep composition",
        "image": "https://your-cdn.com/source.png",
    },
)
print(resp.json()["data"][0]["url"])

Referencia con varias imágenes

Algunos modelos (Nano Banana Edit, GPT-Image-2 Edit) aceptan varias imágenes de referencia.

# nano-banana-edit accepts multiple reference images
resp = requests.post(
    "https://api.kunavo.com/v1/images/edits",
    headers={"Authorization": f"Bearer {API_KEY}"},
    json={
        "model": "nano-banana-edit",
        "prompt": "merge subject from img1 with background from img2",
        "image_urls": [
            "https://your-cdn.com/subject.png",
            "https://your-cdn.com/background.png",
        ],
    },
)

Modelos de edición compatibles

  • nano-banana-edit — edición de Google Nano Banana
  • gpt-image-2-edit — conversión de imagen a imagen de OpenAI

Proporcionar una imagen de origen

Tanto la edición de imágenes como la conversión de imagen a vídeo necesitan una imagen de origen a la que el modelo pueda acceder. Tiene tres opciones; elija la que mejor se adapte a su aplicación:

  • Ya tiene una URL pública: pásela directamente como image (o image_url para vídeo). Eso es todo.
  • Tiene un archivo local: súbalo una vez mediante POST /v1/files y luego reutilice la URL permanente que se devuelve.
  • Tiene bytes sin procesar en el código: inclúyalos en línea como una URI base64 data:; Kunavo los aloja de forma transparente.

Opción A: subir mediante POST /v1/files

Envíe multipart/form-data con un campo file (o un { "file": "data:..." } JSON). Recibirá una URL files.kunavo.com permanente. Se admiten archivos de hasta 25 MB.

# Upload a local file → get a permanent Kunavo URL
import requests

with open("source.png", "rb") as f:
    up = requests.post(
        "https://api.kunavo.com/v1/files",
        headers={"Authorization": f"Bearer {API_KEY}"},
        files={"file": f},
    ).json()

# up["url"] is now a permanent https://files.kunavo.com/... URL
edit = requests.post(
    "https://api.kunavo.com/v1/images/edits",
    headers={"Authorization": f"Bearer {API_KEY}"},
    json={
        "model": "gpt-image-2-edit",
        "prompt": "recolor the crane to bright blue",
        "image": up["url"],
    },
).json()
print(edit["data"][0]["url"])

Opción B: incluir base64 en línea

Omita por completo la carga por separado: coloque una URI data: en el campo image / image_url. Kunavo la decodifica, la aloja en su CDN y proporciona la URL alojada al modelo.

# Or skip the upload step — pass base64 inline, we host it for you.
import base64, requests

with open("source.png", "rb") as f:
    b64 = base64.b64encode(f.read()).decode()

resp = requests.post(
    "https://api.kunavo.com/v1/images/edits",
    headers={"Authorization": f"Bearer {API_KEY}"},
    json={
        "model": "gpt-image-2-edit",
        "prompt": "recolor the crane to bright blue",
        "image": f"data:image/png;base64,{b64}",
    },
)
Lo mismo se aplica a POST /v1/video/generations: image_url acepta una URL https o una URI base64 data: para modelos de imagen a vídeo como Veo.

Formato de la respuesta

Ambos endpoints devuelven la respuesta estándar de imágenes de OpenAI:

{
  "created": 1779360636,
  "data": [
    { "url": "https://files.kunavo.com/image/.../result.png" }
  ]
}

Latencia y tiempos de espera

La generación de imágenes suele tardar entre 5 y 60 segundos, según el modelo. En el modo sincrónico predeterminado, Kunavo mantiene la conexión y consulta el proveedor ascendente durante un máximo de 540 segundos antes de devolver un error 504. Configure el tiempo de espera del cliente como corresponda o use la API asíncrona para enviar la solicitud en segundos y consultar su estado cuando le convenga:

  • Nano Banana/Nano Banana 2: normalmente menos de 10 s.
  • Nano Banana Pro/GPT-Image-2: entre 15 y 60 s.
  • Referencias múltiples + nivel premium: hasta unos 2 minutos.

API asíncrona (envío + consulta de estado/webhook)

Ambos endpoints de imágenes son sincrónicos de forma predeterminada: la llamada mantiene la conexión hasta que el proveedor ascendente genera la imagen y luego devuelve la respuesta estándar de imágenes de OpenAI. Para trabajos por lotes, niveles premium lentos o clientes sin servidor que no pueden mantener una solicitud abierta durante mucho tiempo, añada "async": true (o un webhook_url) a /v1/images/generations o /v1/images/edits.

El envío devuelve inmediatamente un ID img_*; consulte GET /v1/images/{id} hasta que status sea completed o failed. También puede registrar un webhook y omitir por completo las consultas de estado.

# Async: add "async": true (or a webhook_url) to either image endpoint.
# The call returns instantly with an img_ id instead of holding the connection.
import requests, time

API = "https://api.kunavo.com/v1"
H = {"Authorization": f"Bearer {API_KEY}"}

submit = requests.post(
    f"{API}/images/generations",
    headers=H,
    json={"model": "gpt-image-2", "prompt": "a red panda", "async": True},
).json()

task_id = submit["id"]        # "img_abc..."
status  = submit["status"]    # "queued"

# Poll GET /v1/images/{id} until terminal — or skip polling and use a webhook.
while status not in ("completed", "failed"):
    time.sleep(3)
    r = requests.get(f"{API}/images/{task_id}", headers=H).json()
    status = r["status"]

if status == "completed":
    print(r["output"]["url"])
else:
    print("failed:", r["error"])

Objeto de tarea

CampoTipoNotas
idstringID de tarea img_* — pásalo a GET /v1/images/{id}.
statusstringen cola | en curso | completada | fallida.
outputobject|nullAl completarse: { url, urls, archived }. archived es false cuando una imagen no se pudo archivar y su URL es la URL temporal del proveedor.
errorobject|nullSi falla: { code, message }.
expires_atint|nullSegundos Unix, 30 días después del envío: la tarea se puede consultar al menos hasta entonces. Las URL de resultados de la tarea no caducan.
GET /v1/images/{id} está limitado a su propietario: consultar un ID que no le pertenece devuelve 404, indistinguible de uno que nunca se emitió. Frecuencia recomendada de consulta: cada 3 s, con espera exponencial hasta unos 30 s.

Webhooks

Pase webhook_url (https) al enviar la solicitud y Kunavo enviará mediante POST un evento firmado image.completed / image.failed cuando finalice la tarea, con el mismo formato y firma que los webhooks de vídeo y música:

  • X-Kunavo-Webhook-Id — ID de evento estable, idéntico en todos los reintentos (úselo para eliminar duplicados).
  • X-Kunavo-Webhook-Timestamp — segundos de Unix en que se calculó la firma.
  • X-Kunavo-Webhook-Signature — HMAC-SHA256 de sha256= sobre {timestamp}.{rawBody}, con su secreto de webhook como clave.
Los envíos se reintentan con esperas durante unas 9 h. La fila asíncrona se puede consultar durante todo ese tiempo, por lo que siempre es posible recuperar mediante GET un webhook que no se haya recibido.

Mecanismo alternativo para entrada sin procesar

Para los parámetros específicos de cada modelo que Kunavo no traduce (semilla, prompt negativo, formato de salida), pase input. Se envía tal cual al proveedor ascendente, en lugar de la entrada que crearía nuestro adaptador.

El campo que selecciona el nivel de precio de un modelo es la excepción: resolution, o rendering_speed en Ideogram. En un modelo con niveles, siempre se envía como uno de los niveles del modelo y se le factura ese nivel. Cuando input lo omite o proporciona un valor que no corresponde a ninguno de los niveles del modelo, se envía y se factura el nivel predeterminado. El mismo campo en la raíz de la solicitud no se lee cuando se establece input.

# Raw upstream 'input': sent as written, in place of what our adapter builds.
# "resolution" sets the billed tier: 2K here, the default tier when left out.
resp = client.images.generate(
    model="nano-banana-2",
    prompt="",  # ignored when input is set
    extra_body={"input": {
        "prompt": "a futuristic cyberpunk skyline at dusk",
        "aspect_ratio": "16:9",
        "resolution": "2K",
        "output_format": "png",
    }},
)
Al pasar input, se omite la validación de Kunavo. Si el proveedor ascendente rechaza sus campos, recibirá un error 422 de nuestra parte. Consulte la documentación de errores y la documentación del proveedor ascendente del modelo.

Próximos pasos