Documentation
Génération d’images
Deux points de terminaison : texte vers image et retouche d’image / image vers image. Les deux renvoient des URL de résultat permanentes : Kunavo archive chaque image sur son propre CDN.
Kunavo expose /v1/images/generations (texte vers image) et /v1/images/edits (image vers image / retouche). Les deux fonctionnent de manière synchrone par défaut — l’appel reste bloqué jusqu’à ce que le traitement amont soit terminé, puis renvoie les URL des résultats — ou passez en mode asynchrone avec "async": true ou un webhook_url.
Texte vers image
Point de terminaison : POST /v1/images/generations. Utilisez la méthode images.generate du SDK OpenAI ou lancez directement une requête 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)Paramètres courants
| Paramètre | Type | Remarques |
|---|---|---|
model | string | N’importe quel identifiant de modèle d’image figurant dans /v1/models. |
prompt | string | Prompt textuel. Toujours requis. |
size | string | Format OpenAI, par exemple « 1024x1024 ». Converti en rapport hauteur/ |
quality | standard|hd | Lorsqu’il est pris en charge (gpt-image). |
resolution | 1K|2K|4K | Niveau de résolution pour les modèles à niveaux — voir Resolution tiers ci-dessous. La facturation dépend du niveau. |
n | int | Nombre d’images. La plupart des modèles n’en renvoient qu’une, quelle que soit la valeur. |
input | object | Paramètre de secours — voir Raw input ci-dessous. |
files.kunavo.com : Kunavo archive chaque image sur son propre CDN ; contrairement aux URL brutes des fournisseurs en amont, elles n’expirent jamais. Si une image ne peut pas être archivée, son URL est l’URL temporaire du fournisseur en amont, sur un autre hôte : téléchargez cette image et réhébergez-la.Niveaux de résolution
Plusieurs modèles d’image appliquent un tarif progressif selon la résolution de sortie. Transmettez resolution pour choisir un niveau ; si vous l’omettez, le niveau par défaut est utilisé. La facturation porte sur le niveau effectivement produit.
| Modèle (et sa variante -edit) | Niveaux — prix par niveau | Par défaut |
|---|---|---|
| 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 (forfaitaire) | 1K |
La famille veo-3 est également tarifée selon la résolution — les prix par niveau figurent sur la page /models de chaque modèle.
resolution = 4K avec une taille carrée, l’appel est automatiquement ramené à 2K — et facturé à ce niveau.Retouche d’image / image vers image
Point de terminaison : POST /v1/images/edits. Transmettez l’image source sous forme d’URL (HTTPS ou URI base64 data:) via image pour la retouche d’une seule image, ou via image_urls pour des références à plusieurs images.
# 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"])Références à plusieurs images
Certains modèles (Nano Banana Edit, GPT-Image-2 Edit) acceptent plusieurs images de référence.
# 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",
],
},
)Modèles de retouche pris en charge
nano-banana-edit— retouche Google Nano Bananagpt-image-2-edit— conversion d’image en image OpenAI
Fournir une image source
La retouche d’image et la conversion d’image en vidéo nécessitent toutes deux une image source que le modèle peut récupérer. Vous avez trois possibilités — choisissez celle qui convient à votre application :
- Vous disposez déjà d’une URL publique — transmettez-la directement via
image(ouimage_urlpour la vidéo). C’est tout. - Vous avez un fichier local — envoyez-le une seule fois via
POST /v1/files, puis réutilisez l’URL permanente renvoyée. - Vous avez des octets bruts dans votre code — intégrez-les sous forme d’URI base64
data:; Kunavo les héberge de manière transparente.
Option A — téléversement via POST /v1/files
Envoyez multipart/form-data avec un champ file (ou un champ JSON { "file": "data:..." }). Vous recevrez une URL permanente files.kunavo.com — fichiers jusqu’à 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"])Option B — intégration en base64
Évitez complètement le téléversement séparé : placez une URI data: dans le champ image / image_url. Kunavo la décode, l’héberge sur son CDN et transmet l’URL hébergée au modèle.
# 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 accepte une URL https ou une URI base64 data: pour les modèles de conversion d’image en vidéo comme Veo.Structure de la réponse
Les deux points de terminaison renvoient le format standard de réponse d’image d’OpenAI :
{
"created": 1779360636,
"data": [
{ "url": "https://files.kunavo.com/image/.../result.png" }
]
}Latence et délais d’attente
La génération d’images prend généralement entre 5 et 60 secondes, selon le modèle. En mode synchrone par défaut, Kunavo maintient la connexion ouverte et interroge le fournisseur amont pendant un maximum de 540 secondes avant de renvoyer une erreur 504. Réglez le délai d’attente côté client en conséquence — ou utilisez l’API asynchrone pour envoyer la requête en quelques secondes et interroger son état selon votre propre calendrier :
- Nano Banana / Nano Banana 2 : généralement moins de 10 s.
- Nano Banana Pro / GPT-Image-2 : 15 à 60 s.
- Plusieurs références + niveau premium : jusqu’à environ 2 minutes.
API asynchrone (envoi + interrogation / webhook)
Les deux points de terminaison d’image fonctionnent en mode synchrone par défaut — l’appel maintient la connexion ouverte jusqu’à ce que le traitement amont produise l’image, puis renvoie la réponse d’image standard d’OpenAI. Pour les tâches par lots, les niveaux premium lents ou les clients sans serveur qui ne peuvent pas maintenir une requête longue, ajoutez "async": true (ou un webhook_url) à /v1/images/generations ou /v1/images/edits.
L’envoi renvoie immédiatement un identifiant img_* ; interrogez GET /v1/images/{id} jusqu’à ce que status soit completed ou failed — ou inscrivez un webhook et évitez complètement les interrogations.
# 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"])Objet tâche
| Champ | Type | Remarques |
|---|---|---|
id | string | Identifiant de tâche img_* — transmettez-le à GET /v1/ |
status | string | en attente | en cours | terminée | échouée. |
output | object|null | Une fois terminé : { url, urls, archived }. archived vaut false lorsqu’une image n’a pas pu être archivée et que son URL est l’URL temporaire du fournisseur en amont. |
error | object|null | En cas d’échec : { code, message }. |
expires_at | int|null | Secondes Unix, 30 jours après l’envoi : la tâche peut être interrogée au moins jusque-là. Ses URL de résultat n’expirent pas. |
GET /v1/images/{id} est limité au propriétaire : interroger un identifiant qui ne vous appartient pas renvoie 404, sans distinction avec un identifiant qui n’a jamais été attribué. Fréquence d’interrogation recommandée : 3 s, avec un délai exponentiel jusqu’à environ 30 s.Webhooks
Transmettez webhook_url (https) lors de l’envoi ; Kunavo envoie ensuite par POST un événement signé image.completed / image.failed lorsque la tâche se termine — même enveloppe et même signature que pour les webhooks vidéo et musique :
X-Kunavo-Webhook-Id— identifiant d’événement stable, identique lors des nouvelles tentatives (utilisez-le pour éliminer les doublons).X-Kunavo-Webhook-Timestamp— secondes Unix auxquelles la signature a été calculée.X-Kunavo-Webhook-Signature—sha256=HMAC-SHA256 appliqué à{timestamp}.{rawBody}, avec votre secret de webhook comme clé.
Paramètre de secours pour les entrées brutes
Pour les paramètres propres à chaque modèle que Kunavo ne convertit pas (seed, prompt négatif, format de sortie), transmettez input. Il est envoyé tel quel au fournisseur amont, à la place de l’entrée que notre adaptateur aurait construite.
Le champ qui sélectionne le niveau tarifaire d’un modèle fait exception : resolution, ou rendering_speed pour Ideogram. Pour un modèle à niveaux, il est toujours envoyé comme l’un des niveaux de ce modèle, et la facturation correspond à ce niveau. Lorsque input l’omet ou fournit une valeur qui ne correspond à aucun des niveaux du modèle, le niveau par défaut est envoyé et facturé. Le même champ à la racine de la requête n’est pas lu lorsque input est défini.
# 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, vous contournez la validation de Kunavo. Si le fournisseur amont rejette vos champs, vous recevrez une erreur 422 de notre part — consultez la documentation sur les erreurs et la documentation amont du modèle.