Documentation

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ètreTypeRemarques
modelstringN’importe quel identifiant de modèle d’image figurant dans /v1/models.
promptstringPrompt textuel. Toujours requis.
sizestringFormat OpenAI, par exemple « 1024x1024 ». Converti en rapport hauteur/largeur amont.
qualitystandard|hdLorsqu’il est pris en charge (gpt-image).
resolution1K|2K|4KNiveau de résolution pour les modèles à niveaux — voir Resolution tiers ci-dessous. La facturation dépend du niveau.
nintNombre d’images. La plupart des modèles n’en renvoient qu’une, quelle que soit la valeur.
inputobjectParamètre de secours — voir Raw input ci-dessous.
Les URL de résultat sont des liens permanents 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 niveauPar défaut
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 (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.

GPT-Image-2 ne peut pas générer une image 4K avec un rapport hauteur/largeur de 1:1 (carré). Si vous demandez 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 Banana
  • gpt-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 (ou image_url pour 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}",
    },
)
Il en va de même pour 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

ChampTypeRemarques
idstringIdentifiant de tâche img_* — transmettez-le à GET /v1/images/{id}.
statusstringen attente | en cours | terminée | échouée.
outputobject|nullUne 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.
errorobject|nullEn cas d’échec : { code, message }.
expires_atint|nullSecondes 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é.
Les livraisons sont réessayées avec un délai exponentiel pendant environ 9 h. La tâche asynchrone reste interrogeable pendant toute cette période ; un webhook manqué peut donc toujours être récupéré avec GET.

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",
    }},
)
Lorsque vous transmettez 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.

Étapes suivantes