Nano Banana Pro API : tutoriel Python, édition d'image et prix
Un POST, une interrogation, un téléchargement : un script Nano Banana Pro qui fonctionne.

Sur cette page
- Réponse courte
- L'identifiant du modèle et ce qu'il vous faut
- Le script Python
- Retoucher une image existante
- 1K, 2K et 4K : ce que chacun apporte
- Les erreurs que vous allez rencontrer
- Questions fréquentes
- Quel est l'identifiant du modèle de l'API Nano Banana Pro ?
- Combien coûte une image Nano Banana Pro ?
- Nano Banana Pro sait-il dessiner du texte chinois ?
- Faut-il demander du 1K, du 2K ou du 4K ?
- Pourquoi ma retouche a-t-elle renvoyé 400 invalid_request ?
- Sources vérifiées
- Journal des mises à jour
Nano Banana Pro, c'est gemini-3-pro-image de Google, et sur OmniaKey vous l'appelez avec un seul POST /v1/media/tasks. Nos trois essais en 3:4 sont revenus en 896x1200, 1792x2400 et 3584x4800, et chaque mot de l'affiche était correctement orthographié.
Réponse courte
- Modèle :
gemini-3-pro-imageest l'identifiant GA de Google. La fiche du modèle chez Vertex indique une date de sortie au 28 mai 2026. - Appel : envoyez
POST https://api.omniakey.com/v1/media/tasksavec uneIdempotency-Key, interrogezGET /v1/media/tasks/{id}jusqu'au statut succeeded, puis téléchargezassets[0].url. - Paramètres :
parameters.aspect_ratioetparameters.image_size; les valeurs de taille sont 1K, 2K et 4K, avec un K en majuscule. - Limite de requête : 1 MiB pour tout le corps, données d'image en Base64 comprises.
- Prix Google : $0.134 par image 1K/2K et $0.24 par image 4K, d'après la page tarifaire de l'API Gemini.
- Nos jetons : les trois tâches ont déclaré 1,133, 1,225 et 2,480 jetons de sortie. À $120 par million de jetons d'image, cela fait $0.136, $0.147 et $0.298.
- Retouche : utilisez
operation: "edit"et placez l'image source dansinput.imagesous la forme{data, mime_type}.
La page du modèle Nano Banana Pro sur OmniaKey accepte aussi gemini-3-pro-image-preview, l'ancien identifiant d'instantané, au même prix.
L'identifiant du modèle et ce qu'il vous faut
L'identifiant à écrire dans votre code est gemini-3-pro-image. La fiche du modèle chez Vertex le liste en GA avec une date de sortie au 28 mai 2026. Il produit des images en 1K, 2K et 4K.
L'identifiant -preview désigne le même modèle. Le tableau des modèles d'image d'OmniaKey décrit gemini-3-pro-image-preview comme « Same model, -preview snapshot id », au même tarif par appel.
Il vous faut deux choses :
- Une clé d'API OmniaKey, exportée pour que le script la lise :
export OMNIAKEY_API_KEY="your-key". - Python 3. Le script ci-dessous n'utilise que la bibliothèque standard : urllib, json, time, uuid, base64 et pathlib. Aucun SDK à installer.
Le script Python
Trois étapes : créer la tâche, l'interroger, télécharger l'image. Enregistrez-le sous nano_banana.py et lancez python3 nano_banana.py.
import base64
import json
import os
import time
import urllib.request
import uuid
from pathlib import Path
API = "https://api.omniakey.com/v1/media/tasks"
HEADERS = {
"Authorization": f"Bearer {os.environ['OMNIAKEY_API_KEY']}",
"Content-Type": "application/json",
}
def call(url, payload=None, headers=None, method=None):
body = json.dumps(payload).encode() if payload is not None else None
req = urllib.request.Request(url, data=body, headers=headers or HEADERS, method=method)
with urllib.request.urlopen(req, timeout=60) as resp:
return resp.status, json.loads(resp.read())
def create_task(prompt, aspect_ratio="3:4", image_size="2K", image_path=None):
body = {
"model": "gemini-3-pro-image",
"type": "image",
"operation": "generate" if image_path is None else "edit",
"input": {"prompt": prompt},
"parameters": {"aspect_ratio": aspect_ratio, "image_size": image_size},
}
if image_path:
encoded = base64.b64encode(Path(image_path).read_bytes()).decode("utf-8")
body["input"]["image"] = {"data": encoded, "mime_type": "image/png"}
headers = {**HEADERS, "Idempotency-Key": str(uuid.uuid4())}
status, task = call(API, body, headers, "POST")
print("created", task["id"], "HTTP", status)
return task
def wait(task_id, interval=3, timeout=300):
deadline = time.time() + timeout
while time.time() < deadline:
_, task = call(f"{API}/{task_id}")
print(task["status"], task["progress"]["percent"])
if task["status"] in ("succeeded", "failed", "canceled"):
return task
time.sleep(interval)
# A timeout is not a failure: keep the task id and poll it again.
raise TimeoutError(f"task {task_id} is still running")
def download(task, out_path):
asset = task["assets"][0]
with urllib.request.urlopen(asset["url"], timeout=120) as resp:
Path(out_path).write_bytes(resp.read())
print("saved", out_path, asset["mime_type"], asset["byte_size"], "bytes")
if __name__ == "__main__":
task = create_task(
"A vintage travel poster for the Night Train from Zürich to Milano, "
"departing 21:40 from platform 7. A steam train crosses a stone arch "
"bridge below snowy mountains under a deep blue night sky, with a cream "
"border. Spell every word exactly as written.",
aspect_ratio="3:4",
image_size="2K",
)
task = wait(task["id"])
if task["status"] != "succeeded":
raise SystemExit(f"{task['status']}: {task.get('error')}")
download(task, "night-train.jpg")
image_size accepte 1K, 2K ou 4K. Le guide image de Google est explicite : « You must use an uppercase 'K' … Lowercase parameters (e.g., 1k) will be rejected. » Envoyez 2K, pas 2k.
Idempotency-Key est obligatoire. Un UUID neuf par requête est la règle simple ; ne réutilisez une clé que pour renvoyer exactement le même corps. OmniaKey renvoie alors la tâche d'origine en HTTP 200 au lieu de facturer deux fois, et répond 409 si la même clé arrive avec un corps différent.
L'appel de création renvoie 202 avec un id. La documentation des tâches média d'OmniaKey décrit tout le cycle ; la tâche terminée porte les champs que vous lisez :
{
"id": "task_AbMRVqzSnVh0VwBj0S7NuMUxy5sZtfHP",
"status": "succeeded",
"progress": {"percent": 100, "stage": "completed"},
"usage": {"total_tokens": 1133},
"assets": [
{
"kind": "image",
"mime_type": "…",
"url": "https://…signed-url…"
}
]
}
Lisez assets[0].url et téléchargez tout de suite : le lien signé dure environ une heure, et l'enregistrement de la tâche reste 24 heures. Le champ mime_type donne le format ; les modèles Gemini renvoient le plus souvent du JPEG.
Le même script en 1:1 et 2K, avec une consigne d'enseigne en chinois, a donné ceci :

Retoucher une image existante
Mettez operation: "edit" et passez l'image source dans input.image sous la forme {data, mime_type}. Le script ci-dessus le fait déjà quand vous lui donnez un image_path :
task = create_task(
"Hang this poster in a thin black frame on a warm white wall, with a brass "
"picture light above it, a low wooden cabinet below and a trailing plant on "
"the right. Keep the poster exactly as it is.",
aspect_ratio="1:1",
image_size="2K",
image_path="night-train-2k.png",
)
Voici le corps réellement envoyé :
{
"model": "gemini-3-pro-image",
"type": "image",
"operation": "edit",
"input": {
"prompt": "Hang this poster in a thin black frame on a warm white wall…",
"image": {"data": "…base64…", "mime_type": "image/png"}
},
"parameters": {"aspect_ratio": "1:1", "image_size": "2K"}
}
L'image source de l'exemple est un PNG, donc le script l'étiquette image/png ; changez cette étiquette pour un JPEG. Pour plusieurs références, utilisez input.images avec la même forme {data, mime_type} pour chaque entrée. Le guide de Google fixe la limite à 14 images de référence ; pour gemini-3-pro-image, la répartition est de 6 images d'objet, 5 de personnage et 3 de style.
Gardez le corps sous 1 MiB. Le Base64 grossit le fichier d'environ un tiers : réduisez ou compressez la source avant de l'encoder. Notre retouche a utilisé l'affiche en 2K et a conservé chaque mot et la mise en page :

1K, 2K et 4K : ce que chacun apporte
Nous avons lancé la même consigne d'affiche en 3:4 dans les trois tailles. Les pixels correspondaient exactement au tableau de Google pour le 3:4 : 896x1200 en 1K, 1792x2400 en 2K et 3584x4800 en 4K. Le texte de l'affiche était juste à chaque taille.



Ce qui change avec la taille, c'est le détail, pas l'orthographe :
- 1K : l'avant du train est encombré : fanaux, roues et bielles se touchent presque.
- 2K : le village et ses deux clochers apparaissent sur le versant de droite, la cheminée fume d'un filet pâle et le pont montre sept arches.
- 4K : les trois voitures et le tender sont séparés, et la pierre montre des joints d'épaisseur inégale. La mécanique sous la locomotive reste simplifiée.
La durée montait avec la taille : 28.4 s, 48.2 s et 66.9 s. Chaque taille n'a tourné qu'une fois, lisez donc ces secondes comme une seule passe.
Google facture la sortie d'image à $120 par million de jetons, et son tableau donne 1,120 jetons pour le 1K comme pour le 2K et 2,000 jetons pour le 4K. D'où son estimation :
1,120 × $120 ÷ 1,000,000 = $0.134 per 1K image
1,120 × $120 ÷ 1,000,000 = $0.134 per 2K image
2,000 × $120 ÷ 1,000,000 = $0.24 per 4K image
Nos tâches ont déclaré plus de jetons que les exemples de Google. Voici le même calcul avec nos chiffres :
1,133 × $120 ÷ 1,000,000 = $0.136 per 1K image
1,225 × $120 ÷ 1,000,000 = $0.147 per 2K image
2,480 × $120 ÷ 1,000,000 = $0.298 per 4K image
| Taille | Pixels, 3:4 | Notre durée | Nos jetons | Estimation Google |
|---|---|---|---|---|
| 1K | 896x1200 | 28.4 s | 1,133 | $0.134 |
| 2K | 1792x2400 | 48.2 s | 1,225 | $0.134 |
| 4K | 3584x4800 | 66.9 s | 2,480 | $0.24 |
OmniaKey facture un appel d'image à forfait, pas au jeton : son montant ne bouge donc pas avec ces compteurs. Le tarif actuel par appel est sur la page du modèle, et une tâche échouée est remboursée. L'estimation de Google au tarif des jetons pour les mêmes trois images est de $0.134, $0.134 et $0.24.
Les erreurs que vous allez rencontrer
Les échecs listés ici se résument presque toujours à un nom de champ ou à une taille de fichier, pas au modèle. Voici ceux que la documentation média d'OmniaKey indique pour ce point d'entrée :
| HTTP | Code ou statut | Ce que ça veut dire | Que faire |
|---|---|---|---|
| 400 | invalid_request | Corps mal formé, opération non prise en charge ou paramètre invalide | Vérifiez le JSON et les noms de champs ci-dessous |
| 503 | no_available_channel | Aucun canal ne sert ce modèle en ce moment | Changez de modèle ; réessayer n'y changera rien |
| — | failed | La tâche s'est terminée sans résultat | Lisez error.code et error.message |
Une tâche échouée n'est pas une erreur HTTP : l'appel de création a réussi, donc interrogez la tâche et lisez son objet error. Les tâches échouées ou annulées sont remboursées automatiquement.
Une source en pleine résolution envoyée en Base64 peut pousser le corps au-delà de 1 MiB. Réduisez d'abord, puis vérifiez la longueur encodée, pas seulement la taille du fichier.
Le guide de Google refuse un 1k en minuscules. Utilisez 1K, 2K ou 4K.
La documentation image d'OmniaKey refuse aussi size et un mime_type de premier niveau sur les modèles Gemini, car ce ne sont pas des paramètres Gemini. Utilisez parameters.aspect_ratio et parameters.image_size, et lisez le format de sortie dans le champ mime_type de la réponse.
Questions fréquentes
Quel est l'identifiant du modèle de l'API Nano Banana Pro ?
gemini-3-pro-image. La fiche Vertex de Google le donne en GA avec une date de sortie au 28 mai 2026, et OmniaKey accepte le même identifiant. L'ancien identifiant gemini-3-pro-image-preview fonctionne toujours sur OmniaKey et désigne le même modèle.
Combien coûte une image Nano Banana Pro ?
Google estime $0.134 pour une image 1K ou 2K et $0.24 pour une image 4K, à $120 par million de jetons d'image. Nos tâches ont déclaré 1,133, 1,225 et 2,480 jetons, soit $0.136, $0.147 et $0.298 à ce tarif. La page du modèle sur OmniaKey affiche son propre tarif par appel.
Nano Banana Pro sait-il dessiner du texte chinois ?
Oui. Notre enseigne en 2K est revenue avec trois lignes chinoises justes — 同福客栈, 住宿 餐饮 茶水 et 010-6789 4321 — avec les 11 chiffres et le trait d'union.
Faut-il demander du 1K, du 2K ou du 4K ?
Pour une affiche comme la nôtre, 2K est le bon milieu. Les trois tailles ont écrit notre affiche correctement : le 4K achète donc du détail plus fin — voitures séparées, joints de briques — et non un meilleur texte. Prenez 1K pour les brouillons où 896x1200 suffit.
Pourquoi ma retouche a-t-elle renvoyé 400 invalid_request ?
Les causes habituelles : un corps de plus de 1 MiB, la source dans le mauvais champ, ou un modèle Gemini qui reçoit size ou un mime_type de premier niveau. Placez l'image dans input.image sous la forme {data, mime_type}, gardez le corps encodé sous 1 MiB et utilisez aspect_ratio et image_size.
Sources vérifiées
- Google Cloud : fiche du modèle Gemini 3 Pro Image — vérifiée le 3 novembre 2026.
- Google : guide de génération d'images de l'API Gemini — vérifié le 3 novembre 2026.
- Google : tarifs de l'API Gemini — vérifiés le 3 novembre 2026.
- Google : annonce de Nano Banana Pro — vérifiée le 3 novembre 2026.
Journal des mises à jour
- 2026-11-03 : première version ; cinq appels de test passés ce jour-là via OmniaKey.
Modèles cités dans cet article
Articles similaires
Nano Banana 2.1 : accès API, prix et migration
Comparez Nano Banana 2.1 à Nano Banana 2, puis créez des tâches image prises en charge dans OmniaKey.
Photos produit avec Nano Banana : 8 prompts testés
Huit prompts, 22 retouches, deux modèles : quelles prises ont gardé l'étiquette, où la chaussure a été mise en miroir et quel modèle choisir pour chaque travail.
Seedream 5.0 Pro vs Nano Banana Pro : test à prompt identique et prix
Cinq prompts identiques, deux modèles, des temps mesurés et le prix par image 2K.
