> ## Documentation Index
> Fetch the complete documentation index at: https://docs.bettertoken.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# API Nano Banana : génération, références et retouches

> Connectez Nano Banana Pro, 2 et 2.1 à BetterToken : authentification, résolutions, Python, images de référence, enregistrement, retouches et limites de l’API.

Le même endpoint natif Gemini sert à générer depuis du texte, retoucher une référence et poursuivre les retouches. Les exemples utilisent `nano-banana-2.1` ; remplacez le modèle dans l’URL ou le SDK pour les deux autres.

* [API Gemini de génération par texte](/fr/api-reference/gemini-images-generations)
* [API Gemini de retouche d’images](/fr/api-reference/gemini-images-edits)

<Warning>
  BetterToken API ne prend pas en charge la génération avec recherche, y compris Google Web Search et Image Search grounding. N’ajoutez pas d’outils de recherche.
</Warning>

## Connexion

| Champ | Valeur |
| - | - |
| Base URL | `https://bettertoken.ai` |
| Requête | `POST /v1beta/models/{model}:generateContent` |
| Authentification | `x-goog-api-key: YOUR_API_KEY` ou `Authorization: Bearer YOUR_API_KEY`. Choisissez une méthode. |
| Corps | `application/json` |
| Model IDs | `nano-banana-pro`, `nano-banana-2`, `nano-banana-2.1` |

<a href={"https://bettertoken.ai/register"}>Créer une BetterToken API Key</a> · <a href={"https://bettertoken.ai/pricing"}>catalogue de modèles</a> · [Présentation des modèles Nano Banana](/fr/model-updates/nano-banana)

<Warning>
  Ces trois modèles n’acceptent pas `POST /v1/images/generations` ni `POST /v1/images/edits` : réponse `400 unsupported_endpoint`. Ne réutilisez pas les exemples GPT Image avec multipart, `image[]` ou `data[].b64_json`.
</Warning>

## Générer une première image

Définissez `BETTERTOKEN_API_KEY` dans le terminal, puis exécutez la requête. Elle attend la génération et enregistre le JSON complet dans `response.json`.

<Tabs>
  <Tab title="macOS / Linux">
    ```bash theme={null}
    export BETTERTOKEN_API_KEY="YOUR_API_KEY"

    curl --fail-with-body --max-time 650 \
      "https://bettertoken.ai/v1beta/models/nano-banana-2.1:generateContent" \
      -H "x-goog-api-key: $BETTERTOKEN_API_KEY" \
      -H "Content-Type: application/json" \
      -H "X-BetterToken-Max-Images: 1" \
      -d '{
        "contents": [{
          "role": "user",
          "parts": [{"text": "Une photo de studio d’une tasse en céramique bleue sur une table blanche."}]
        }],
        "generationConfig": {
          "responseModalities": ["IMAGE"],
          "candidateCount": 1,
          "imageConfig": {"imageSize": "1K", "aspectRatio": "1:1"}
        }
      }' -o response.json
    ```
  </Tab>

  <Tab title="Windows PowerShell">
    ```powershell theme={null}
    $env:BETTERTOKEN_API_KEY = "YOUR_API_KEY"
    $headers = @{
        "x-goog-api-key" = $env:BETTERTOKEN_API_KEY
        "X-BetterToken-Max-Images" = "1"
    }
    $body = @{
        contents = @(@{
            role = "user"
            parts = @(@{ text = "Une photo de studio d’une tasse en céramique bleue sur une table blanche." })
        })
        generationConfig = @{
            responseModalities = @("IMAGE")
            candidateCount = 1
            imageConfig = @{ imageSize = "1K"; aspectRatio = "1:1" }
        }
    } | ConvertTo-Json -Depth 10
    Invoke-WebRequest `
        -Uri "https://bettertoken.ai/v1beta/models/nano-banana-2.1:generateContent" `
        -Method Post `
        -Headers $headers `
        -ContentType "application/json" `
        -Body ([System.Text.Encoding]::UTF8.GetBytes($body)) `
        -TimeoutSec 650 `
        -OutFile "response.json"
    ```
  </Tab>
</Tabs>

Passez `imageSize` à `2K` ou `4K` pour une résolution supérieure. Commencez par `1K`, `1:1` et une image. N’activez pas les relances automatiques avec `--retry`.

## Paramètres courants

Pour une photo de produit, décrivez l’objet, la matière, l’éclairage et le fond. Pour une affiche, précisez le texte exact et la disposition. Pour une retouche, indiquez quoi modifier et quoi conserver.

HTTP natif utilise ces champs ; le SDK Python utilise snake\_case. Placez les réglages dans `generationConfig.imageConfig`.

| Champ | Valeur |
| - | - |
| `contents[].parts[].text` | Décrivez sujet, fond, style et modifications. |
| `contents[].parts[].inlineData` | `mimeType` et base64 du fichier original de référence, pas une URL. |
| `generationConfig.responseModalities` | Définissez explicitement `["IMAGE"]`. |
| `generationConfig.imageConfig.imageSize` | `1K`, `2K` ou `4K`, sensible à la casse ; défaut `1K`. |
| `generationConfig.imageConfig.aspectRatio` | Choisissez les proportions du modèle dans le tableau ci-dessous ; les exemples utilisent `1:1`. |
| `generationConfig.candidateCount` | Omettez ou indiquez l’entier `1` ; pas de `n` à la racine native. |
| `X-BetterToken-Max-Images` | En-tête facultatif : entier de `1` à `4`, défaut `1`. Maximum d’images autorisées pour livraison et facturation. |

<span id="aspect-ratios" />

### Proportions prises en charge par Google

Nano Banana 2 et 2.1 acceptent 14 proportions ; Pro en accepte 10. Commencez par `1:1` pour la première requête.

| Modèle | Résolution | Proportions |
| - | - | - |
| `nano-banana-pro` | `1K`, `2K`, `4K` | `1:1`, `2:3`, `3:2`, `3:4`, `4:3`, `4:5`, `5:4`, `9:16`, `16:9`, `21:9` |
| `nano-banana-2` | `1K`, `2K`, `4K` | `1:1`, `1:4`, `1:8`, `2:3`, `3:2`, `3:4`, `4:1`, `4:3`, `4:5`, `5:4`, `8:1`, `9:16`, `16:9`, `21:9` |
| `nano-banana-2.1` | `1K`, `2K`, `4K` | `1:1`, `1:4`, `1:8`, `2:3`, `3:2`, `3:4`, `4:1`, `4:3`, `4:5`, `5:4`, `8:1`, `9:16`, `16:9`, `21:9` |

[Référence Google des proportions et tailles d’image](https://ai.google.dev/gemini-api/docs/image-generation#aspect-ratios-and-image-size)

Ce plafond ne garantit pas le nombre d’images. Le modèle peut en renvoyer une malgré une demande multiple. Pour un nombre fixe, envoyez des requêtes séparées.

## Lire et enregistrer les images

Les images se trouvent dans `candidates[].content.parts[].inlineData`. La structure ci-dessous utilise le marqueur `BASE64_IMAGE_DATA`. Parcourez toutes les parties finales et ignorez `thought: true`.

```json theme={null}
{
  "candidates": [{
    "content": {
      "role": "model",
      "parts": [{
        "inlineData": {
          "mimeType": "image/jpeg",
          "data": "BASE64_IMAGE_DATA"
        }
      }]
    },
    "finishReason": "STOP"
  }]
}
```

Ce code Python enregistre le résultat curl. Choisissez l’extension selon `mimeType` : une image peut être JPEG, pas toujours `.png`.

```python theme={null}
import base64
import json
from pathlib import Path

suffixes = {"image/png": ".png", "image/jpeg": ".jpg"}
result = json.loads(Path("response.json").read_text())
saved = 0
for candidate in result.get("candidates", []):
    for part in candidate.get("content", {}).get("parts", []):
        if part.get("thought"):
            continue
        blob = part.get("inlineData")
        if not blob:
            continue
        suffix = suffixes.get(blob["mimeType"])
        if suffix is None:
            raise ValueError("Unexpected image MIME type: " + blob["mimeType"])
        saved += 1
        Path(f"generated-{saved}{suffix}").write_bytes(
            base64.b64decode(blob["data"], validate=True)
        )
if saved == 0:
    raise RuntimeError("No final image returned; inspect response.json.")
```

## Exemple complet du SDK Python

Utilisez Python 3.10 ou ultérieur et `google-genai==2.30.1`. Installez dans l’environnement virtuel du projet ; les anciennes versions peuvent omettre `image_size`.

```bash theme={null}
python -m pip install "google-genai==2.30.1"
```

Le Base URL du SDK est la racine du domaine sans `/v1` ni `/v1beta`. `timeout` est en millisecondes et `attempts=1` désactive les relances. `save_images` enregistre toutes les images finales.

```python theme={null}
import os
from pathlib import Path
from google import genai
from google.genai import types

MODEL = "nano-banana-2.1"
client = genai.Client(
    vertexai=False,
    api_key=os.environ["BETTERTOKEN_API_KEY"],
    http_options=types.HttpOptions(
        base_url="https://bettertoken.ai",
        api_version="v1beta",
        timeout=650_000,
        retry_options=types.HttpRetryOptions(attempts=1),
        headers={"X-BetterToken-Max-Images": "1"},
    ),
)
config = types.GenerateContentConfig(
    response_modalities=["IMAGE"],
    candidate_count=1,
    image_config=types.ImageConfig(image_size="1K", aspect_ratio="1:1"),
)

def save_images(response, prefix):
    if len(response.candidates or []) != 1 or not response.candidates[0].content:
        raise RuntimeError("No single image candidate returned.")
    saved = 0
    suffixes = {"image/png": ".png", "image/jpeg": ".jpg"}
    for part in response.candidates[0].content.parts or []:
        if part.thought or not part.inline_data:
            continue
        blob = part.inline_data
        suffix = suffixes.get(blob.mime_type)
        if suffix is None:
            raise ValueError("Unexpected image MIME type: " + str(blob.mime_type))
        saved += 1
        Path(f"{prefix}-{saved}{suffix}").write_bytes(blob.data)
    if saved == 0:
        raise RuntimeError("No final image returned; inspect the response.")

first_turn = types.Content(
    role="user",
    parts=[types.Part(text="Une photo de studio d’une tasse en céramique bleue sur une table blanche.")],
)
response = client.models.generate_content(
    model=MODEL, contents=[first_turn], config=config,
)
save_images(response, "generated")
```

## Envoyer une référence

Exécutez après l’exemple Python pour envoyer une nouvelle retouche. Remplacez `reference.jpg` par votre fichier. Pour PNG, utilisez `mime_type="image/png"`. Ajoutez d’autres références dans `parts` du même message utilisateur.

```python theme={null}
first_turn = types.Content(
    role="user",
    parts=[
        types.Part(text="Rendez la tasse rouge. Conservez sa forme et le fond."),
        types.Part.from_bytes(
            data=Path("reference.jpg").read_bytes(),
            mime_type="image/jpeg",
        ),
    ],
)
response = client.models.generate_content(
    model=MODEL, contents=[first_turn], config=config,
)
save_images(response, "reference-edit")
```

En JSON natif, utilisez `inlineData: {"mimeType": "image/jpeg", "data": "BASE64_IMAGE_DATA"}`. Encodez les octets originaux sans préfixe `data:image/...;base64,`. N’utilisez ni multipart, ni Files, ni `fileData`.

## Poursuivre les retouches

Exécutez après une génération ou retouche réussie. Conservez le `content` complet, l’ordre des parties et `thoughtSignature`. Ne reconstruisez pas l’historique à partir de la seule image ; n’inventez ni ne modifiez de signature.

```python theme={null}
history = [first_turn, response.candidates[0].content]
edit_turn = types.Content(
    role="user",
    parts=[types.Part(text="Ajoutez une petite anse dorée. Gardez tout le reste identique.")],
)
edited = client.models.generate_content(
    model=MODEL, contents=[*history, edit_turn], config=config,
)
save_images(edited, "follow-up")
history.extend([edit_turn, edited.candidates[0].content])
```

Chaque tour est une nouvelle génération. Gardez tout le `history`, ajoutez l’instruction puis le `content` reçu. N’utilisez pas `previous_interaction_id` d’Interactions ici.

## Prise en charge de l’API

* Utilisez `generateContent` sans streaming. Cette intégration ne prend pas en charge Files / `fileData`, Batch, Interactions ni le streaming.
* `responseMimeType`, `responseSchema` et les formats de compression personnalisés ne sont pas pris en charge. Dans `imageConfig`, utilisez seulement les deux champs indiqués ci-dessus.
* Omettez `cachedContent`, les appels de fonctions, l’exécution de code, la recherche de fichiers, Maps, URL context et les réglages d’entrée ou de génération audio.

## Avec un client OpenAI Chat existant

Vous pouvez appeler `POST /v1/chat/completions` avec Base URL `https://bettertoken.ai/v1`. Pour une nouvelle intégration, les références et les retouches successives, utilisez l’API native Gemini ci-dessus. Dans Chat, omettez `n` ou indiquez l’entier `1`.

En HTTP, placez `google.image_config` à la racine JSON. Dans le SDK Python OpenAI, utilisez `extra_body`, fusionné à la racine par le SDK. Pas de `generationConfig` ici.

```bash theme={null}
curl --fail-with-body --max-time 650 \
  "https://bettertoken.ai/v1/chat/completions" \
  -H "Authorization: Bearer $BETTERTOKEN_API_KEY" \
  -H "Content-Type: application/json" \
  -H "X-BetterToken-Max-Images: 1" \
  -d '{
    "model": "nano-banana-2.1",
    "messages": [{"role": "user", "content": "Une tasse en céramique bleue sur une table blanche."}],
    "n": 1,
    "stream": false,
    "google": {"image_config": {"image_size": "1K", "aspect_ratio": "1:1"}}
  }'
```

Pour l’exemple SDK Python OpenAI, installez `openai==1.66.2` dans le même environnement virtuel :

```python theme={null}
import base64
import os
import re
from pathlib import Path
from openai import OpenAI

client = OpenAI(
    api_key=os.environ["BETTERTOKEN_API_KEY"],
    base_url="https://bettertoken.ai/v1",
    max_retries=0,
    timeout=650,
)
response = client.chat.completions.create(
    model="nano-banana-2.1",
    messages=[{"role": "user", "content": "Une tasse en céramique bleue sur une table blanche."}],
    n=1,
    stream=False,
    extra_headers={"X-BetterToken-Max-Images": "1"},
    extra_body={
        "google": {"image_config": {"image_size": "1K", "aspect_ratio": "1:1"}}
    },
)
content = response.choices[0].message.content or ""
images = re.findall(r"data:(image/(?:png|jpeg));base64,([A-Za-z0-9+/=]+)", content)
if not images:
    raise RuntimeError("No inline image in Chat response.")
for index, (mime, data) in enumerate(images, 1):
    suffix = ".png" if mime == "image/png" else ".jpg"
    Path(f"chat-{index}{suffix}").write_bytes(base64.b64decode(data, validate=True))
```

Chat renvoie des Markdown Data URL dans `choices[0].message.content`, pas le `data[]` d’Images API. Ne reconstruisez pas de signatures depuis ce texte ; utilisez la retouche native.

## Erreurs courantes

| Problème | Action |
| - | - |
| `401` / Key invalide | Utilisez une BetterToken API Key, pas Google. Vérifiez variable et en-tête. |
| `404` / URL | Base URL racine, `api_version="v1beta"`, et un des trois Model IDs publics. |
| `400 unsupported_endpoint` | Remplacez `/v1/images/*` par `:generateContent`. |
| `400` / paramètres | Vérifiez les niveaux, la casse de `1K/2K/4K` et les proportions du modèle. Omettez `candidateCount` ou indiquez l’entier `1` ; n’ajoutez pas d’outils de recherche. |
| Aucune image finale | Examinez erreurs, sécurité, texte et `finishReason`. Les images thought ne sont pas finales. |
| Fichier illisible | Décodez le base64 et utilisez l’extension MIME, sans enregistrer tout le JSON ou Markdown. |
| Expiration ou déconnexion | Vérifiez la consommation et gardez l’ID de requête. Confirmez le résultat avec le support avant une relance pour éviter doublons et frais. |

Les images arrivent dans la réponse courante. Ce flux n’offre ni récupération en arrière-plan ni interrogation de tâche. Enregistrez les résultats, prévoyez assez de temps côté SDK et proxy et désactivez les relances automatiques.

## Sources officielles

* [Modèle Nano Banana Pro](https://ai.google.dev/gemini-api/docs/models/gemini-3-pro-image)
* [Modèle Nano Banana 2](https://ai.google.dev/gemini-api/docs/models/gemini-3.1-flash-image)
* [Modèle Nano Banana 2.1](https://ai.google.dev/gemini-api/docs/models/gemini-nano-banana-2.1)
* [Guide des images Google](https://ai.google.dev/gemini-api/docs/generate-content/image-generation)
* [Notes de version Google](https://ai.google.dev/gemini-api/docs/changelog)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.