> ## 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: geração, referências e edição

> Conecte Nano Banana Pro, 2 e 2.1 à BetterToken: autenticação, resoluções, Python, imagens de referência, salvamento, edição em várias etapas e limites da API.

Use o mesmo endpoint Gemini nativo para texto, referências e edições seguintes. Os exemplos usam `nano-banana-2.1`; substitua o modelo na URL ou no SDK para usar os outros dois.

* [API de texto para imagem do Gemini](/pt-br/api-reference/gemini-images-generations)
* [API de edição de imagens do Gemini](/pt-br/api-reference/gemini-images-edits)

<Warning>
  A BetterToken API não oferece geração com pesquisa, incluindo Google Web Search e Image Search grounding. Não adicione ferramentas de pesquisa.
</Warning>

## Dados de conexão

| Campo | Valor |
| - | - |
| Base URL | `https://bettertoken.ai` |
| Requisição | `POST /v1beta/models/{model}:generateContent` |
| Autenticação | `x-goog-api-key: YOUR_API_KEY` ou `Authorization: Bearer YOUR_API_KEY`. Escolha um. |
| Corpo | `application/json` |
| Model IDs | `nano-banana-pro`, `nano-banana-2`, `nano-banana-2.1` |

<a href={"https://bettertoken.ai/register"}>Criar uma BetterToken API Key</a> · <a href={"https://bettertoken.ai/pricing"}>catálogo de modelos</a> · [Apresentação dos modelos Nano Banana](/pt-br/model-updates/nano-banana)

<Warning>
  Estes três modelos não aceitam `POST /v1/images/generations` nem `POST /v1/images/edits`: retornam `400 unsupported_endpoint`. Não reutilize exemplos GPT Image com multipart, `image[]` ou `data[].b64_json`.
</Warning>

## Gere a primeira imagem

Defina `BETTERTOKEN_API_KEY` no terminal e execute. A chamada aguarda a geração e salva o JSON completo em `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": "Uma foto de estúdio de uma caneca de cerâmica azul em uma mesa branca."}]
        }],
        "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 = "Uma foto de estúdio de uma caneca de cerâmica azul em uma mesa branca." })
        })
        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>

Mude `imageSize` para `2K` ou `4K` para maior resolução. Comece com `1K`, `1:1` e uma imagem. Não ative novas tentativas automáticas com `--retry`.

## Parâmetros comuns

Para fotos de produto, descreva objeto, material, iluminação e fundo. Para cartazes, indique o texto exato e a disposição. Ao editar, diga o que deve mudar e o que deve ser preservado.

HTTP nativo usa os campos abaixo; Python SDK usa snake\_case. Coloque as opções dentro de `generationConfig.imageConfig`.

| Campo | Valor |
| - | - |
| `contents[].parts[].text` | Descreva objeto, fundo, estilo e alterações. |
| `contents[].parts[].inlineData` | `mimeType` e base64 dos bytes originais da referência, não URL. |
| `generationConfig.responseModalities` | Defina `["IMAGE"]` explicitamente. |
| `generationConfig.imageConfig.imageSize` | `1K`, `2K` ou `4K`, com maiúsculas; padrão `1K`. |
| `generationConfig.imageConfig.aspectRatio` | Escolha a proporção do modelo na tabela abaixo; os exemplos usam `1:1`. |
| `generationConfig.candidateCount` | Omita ou use inteiro `1`; não envie `n` na raiz nativa. |
| `X-BetterToken-Max-Images` | Cabeçalho opcional: inteiro `1` a `4`, padrão `1`. Máximo de imagens autorizado para entrega e cobrança. |

<span id="aspect-ratios" />

### Proporções aceitas pelo Google

Nano Banana 2 e 2.1 aceitam 14 proporções; Pro aceita 10. Comece com `1:1` na primeira requisição.

| Modelo | Resolução | Proporções |
| - | - | - |
| `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` |

[Referência de proporções e tamanhos do Google](https://ai.google.dev/gemini-api/docs/image-generation#aspect-ratios-and-image-size)

Esse máximo não garante a quantidade. O modelo pode retornar uma imagem mesmo se pedir várias. Para quantidade fixa, envie requisições separadas.

## Leia e salve a imagem

As imagens estão em `candidates[].content.parts[].inlineData`. A estrutura abaixo usa o marcador `BASE64_IMAGE_DATA`. Percorra todas as partes finais e ignore `thought: true`.

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

Este Python salva o resultado de curl. Escolha a extensão pelo `mimeType`; a imagem pode ser JPEG, não sempre `.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.")
```

## Exemplo completo com Python SDK

Use Python 3.10 ou mais recente e `google-genai==2.30.1`. Instale no ambiente virtual do projeto; versões antigas podem omitir `image_size`.

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

O Base URL do SDK é a raiz do domínio, sem `/v1` ou `/v1beta`. `timeout` usa milissegundos e `attempts=1` desativa tentativas automáticas. `save_images` salva todas as imagens finais.

```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="Uma foto de estúdio de uma caneca de cerâmica azul em uma mesa branca.")],
)
response = client.models.generate_content(
    model=MODEL, contents=[first_turn], config=config,
)
save_images(response, "generated")
```

## Envie uma referência

Execute depois do exemplo Python para enviar uma nova edição. Troque `reference.jpg` pelo arquivo local. Para PNG use `mime_type="image/png"`. Adicione outras referências em `parts` da mesma mensagem.

```python theme={null}
first_turn = types.Content(
    role="user",
    parts=[
        types.Part(text="Mude a caneca para vermelho. Preserve a forma e o fundo."),
        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")
```

No JSON nativo use `inlineData: {"mimeType": "image/jpeg", "data": "BASE64_IMAGE_DATA"}`. Codifique os bytes originais sem o prefixo `data:image/...;base64,`. Não use multipart, Files ou `fileData`.

## Continue editando

Execute após uma geração ou edição bem-sucedida. Preserve todo o `content` da resposta, a ordem das partes e `thoughtSignature`. Não recrie o histórico apenas pela imagem nem invente ou altere assinaturas.

```python theme={null}
history = [first_turn, response.candidates[0].content]
edit_turn = types.Content(
    role="user",
    parts=[types.Part(text="Adicione uma pequena alça dourada. Mantenha o restante igual.")],
)
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])
```

Cada etapa é uma nova geração. Preserve `history`, acrescente a instrução e depois o `content` recebido. Não use `previous_interaction_id` de Interactions aqui.

## Suporte da API

* Use `generateContent` sem streaming. Esta integração não aceita Files / `fileData`, Batch, Interactions nem streaming.
* `responseMimeType`, `responseSchema` e formatos de compressão personalizados não são aceitos. Em `imageConfig`, use apenas os dois campos listados acima.
* Omita `cachedContent`, chamadas de funções, execução de código, busca de arquivos, Maps, URL context e configurações de entrada ou geração de áudio.

## Se já usa um cliente OpenAI Chat

Você pode chamar `POST /v1/chat/completions` com Base URL `https://bettertoken.ai/v1`. Para novas integrações, referências e edição em várias etapas, use a API nativa Gemini acima. Em Chat, omita `n` ou use o inteiro `1`.

Em HTTP, `google.image_config` fica na raiz JSON. No Python OpenAI SDK, use `extra_body`, que é mesclado na raiz. Não use `generationConfig` aqui.

```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": "Uma caneca de cerâmica azul em uma mesa branca."}],
    "n": 1,
    "stream": false,
    "google": {"image_config": {"image_size": "1K", "aspect_ratio": "1:1"}}
  }'
```

Para o exemplo Python OpenAI SDK, instale `openai==1.66.2` no mesmo ambiente virtual:

```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": "Uma caneca de cerâmica azul em uma mesa branca."}],
    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 retorna Markdown Data URL em `choices[0].message.content`, não o `data[]` de Images API. Não reconstrua assinaturas desse texto; use a edição nativa.

## Erros comuns

| Problema | Ação |
| - | - |
| `401` / Key inválida | Use BetterToken API Key, não Google. Confira variável e cabeçalho. |
| `404` / URL | Base URL raiz, `api_version="v1beta"` e um dos três Model IDs públicos. |
| `400 unsupported_endpoint` | Troque `/v1/images/*` por `:generateContent`. |
| `400` / parâmetros | Confira os níveis, as maiúsculas de `1K/2K/4K` e as proporções do modelo. Omita `candidateCount` ou use o inteiro `1`; não adicione ferramentas de pesquisa. |
| Sem imagem final | Inspecione erros, segurança, texto e `finishReason`. Não salve imagens thought como finais. |
| Arquivo não abre | Decodifique base64 e use extensão MIME, não salve JSON ou Markdown inteiro. |
| Timeout ou desconexão | Confira consumo e guarde o ID de requisição. Confirme o resultado com suporte antes de tentar de novo, evitando duplicação e cobrança. |

As imagens chegam na resposta atual. Não há recuperação em segundo plano ou consulta de tarefa neste fluxo. Salve os resultados, reserve tempo no SDK e proxy e desative tentativas automáticas.

## Fontes oficiais

* [Modelo Nano Banana Pro](https://ai.google.dev/gemini-api/docs/models/gemini-3-pro-image)
* [Modelo Nano Banana 2](https://ai.google.dev/gemini-api/docs/models/gemini-3.1-flash-image)
* [Modelo Nano Banana 2.1](https://ai.google.dev/gemini-api/docs/models/gemini-nano-banana-2.1)
* [Guia de imagens do Google](https://ai.google.dev/gemini-api/docs/generate-content/image-generation)
* [Notas de versão do Google](https://ai.google.dev/gemini-api/docs/changelog)


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