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ámetro | Tipo | Notas |
|---|---|---|
model | string | Cualquier slug de modelo de imagen de /v1/models. |
prompt | string | Instrucción de texto. Siempre es obligatoria. |
size | string | Formato de OpenAI, como "1024x1024". Se transforma en una relación de aspecto del proveedor ascendente. |
quality | standard|hd | Cuando sea compatible (gpt-image). |
resolution | 1K|2K|4K | Nivel de resolución para modelos con niveles; consulte más abajo Resolution tiers. Se factura según el nivel. |
n | int | Número de imágenes. La mayoría de los modelos siempre devuelven 1. |
input | object | Mecanismo alternativo; consulte más abajo Raw input. |
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 uno | Predeterminado |
|---|---|---|
| nano-banana-2 | 1K $0.0469 · 2K $0.0707 · 4K $0.1057 | 1K |
| nano-banana-pro | 1K / 2K $0.067 · 4K $0.12 | 2K |
| gpt-image-2 | 1K / 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.
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 Bananagpt-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(oimage_urlpara vídeo). Eso es todo. - Tiene un archivo local: súbalo una vez mediante
POST /v1/filesy 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}",
},
)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
| Campo | Tipo | Notas |
|---|---|---|
id | string | ID de tarea img_* — pásalo a GET /v1/ |
status | string | en cola | en curso | completada | fallida. |
output | object|null | Al completarse: { url, urls, archived }. archived es false cuando una imagen no se pudo archivar y su URL es la URL temporal del proveedor. |
error | object|null | Si falla: { code, message }. |
expires_at | int|null | Segundos 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 desha256=sobre{timestamp}.{rawBody}, con su secreto de webhook como clave.
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",
}},
)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.