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

# SDK quickstart

> Generate, edit, and stream images with the google-genai SDK.

This guide uses Google's official Python SDK. The only BananaHub-specific step is overriding `base_url`. See [Gemini-compatible API](/gemini/overview) for the concept.

<Note>
  You'll need an active API key with permission for the model you call. See [Authentication](/authentication).
</Note>

## 1. Install and configure

```bash theme={null}
pip install google-genai
```

Point the client at BananaHub and pass your API key:

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

client = genai.Client(
    api_key="YOUR_BANANAHUB_KEY",
    http_options=types.HttpOptions(base_url="https://bananahub.io/api/gemini"),
)
```

<Tip>
  Any Gemini client works the same way — set the base URL to `https://bananahub.io/api/gemini` and send your key as `x-goog-api-key`.
</Tip>

## 2. Text-to-image

Request the `IMAGE` modality and read the base64 image from the first candidate.

<CodeGroup>
  ```python Python theme={null}
  resp = client.models.generate_content(
      model="gemini-2.5-flash-image",
      contents="a red panda astronaut floating in a nebula",
      config=types.GenerateContentConfig(
          response_modalities=["IMAGE"],
          image_config=types.ImageConfig(aspect_ratio="16:9"),
      ),
  )

  image = resp.candidates[0].content.parts[0].inline_data.data  # raw PNG bytes
  open("out.png", "wb").write(image)
  ```

  ```bash cURL theme={null}
  curl -s -X POST \
    "https://bananahub.io/api/gemini/v1beta/models/gemini-2.5-flash-image:generateContent" \
    -H "x-goog-api-key: $API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "contents": [{"parts": [{"text": "a red panda astronaut floating in a nebula"}]}],
      "generationConfig": {
        "responseModalities": ["IMAGE"],
        "imageConfig": {"aspectRatio": "16:9"}
      }
    }'
  ```
</CodeGroup>

The response is standard Gemini JSON. The image is base64 in `candidates[0].content.parts[0].inlineData.data`.

### Resolution

For **NanoBanana 2** and **Pro**, select the output size with `imageSize` — `1K`, `2K`, `4K`, plus `512px` on NanoBanana 2:

```python theme={null}
config=types.GenerateContentConfig(
    response_modalities=["IMAGE"],
    image_config=types.ImageConfig(aspect_ratio="1:1", image_size="2K"),
)
```

<Info>
  `imageSize` is validated by the model — supported values are `1K`, `2K`, `4K` (plus `512px` on NanoBanana 2); anything else returns `400 INVALID_ARGUMENT`. NanoBanana (`gemini-2.5-flash-image`) outputs `1K`. Sizes below `1K` (e.g. `512px`) are billed at the `1K` rate.
</Info>

## 3. Image-to-image (edit)

Pass one or more input images plus an instruction in `contents`.

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

resp = client.models.generate_content(
    model="gemini-3-pro-image",
    contents=[
        types.Part.from_bytes(data=Path("input.png").read_bytes(), mime_type="image/png"),
        "add a tiny astronaut helmet",
    ],
    config=types.GenerateContentConfig(response_modalities=["IMAGE"]),
)

open("edited.png", "wb").write(resp.candidates[0].content.parts[0].inline_data.data)
```

## 4. Streaming

Use `generate_content_stream` to receive the response as it's produced.

```python theme={null}
stream = client.models.generate_content_stream(
    model="gemini-2.5-flash-image",
    contents="a watercolor banana wearing tiny sunglasses",
    config=types.GenerateContentConfig(response_modalities=["IMAGE"]),
)

for chunk in stream:
    for part in chunk.candidates[0].content.parts or []:
        if part.inline_data and part.inline_data.data:
            open("out.png", "wb").write(part.inline_data.data)
```

The raw HTTP endpoint is `:streamGenerateContent?alt=sse`, which returns Server-Sent Events (`data: {json}` frames) — exactly what the SDK consumes.

## 5. Count tokens

`countTokens` is proxied straight to Google, so you get a real token count for your request — useful for budgeting before you generate.

<CodeGroup>
  ```python Python theme={null}
  result = client.models.count_tokens(
      model="gemini-3-pro-image",
      contents="a red panda astronaut floating in a nebula",
  )
  print(result.total_tokens)
  ```

  ```bash cURL theme={null}
  curl -s -X POST \
    "https://bananahub.io/api/gemini/v1beta/models/gemini-3-pro-image:countTokens" \
    -H "x-goog-api-key: $API_KEY" \
    -H "Content-Type: application/json" \
    -d '{"contents": [{"parts": [{"text": "a red panda astronaut floating in a nebula"}]}]}'
  ```
</CodeGroup>

<Info>
  Preview model ids are supported here too — see [Models](/gemini/overview#models).
</Info>

## 6. Handle errors

BananaHub returns errors in the Gemini envelope, so the SDK raises `errors.APIError` with the canonical status:

```python theme={null}
from google.genai import errors

try:
    resp = client.models.generate_content(
        model="gemini-3-pro-image",
        contents="a red panda",
        config=types.GenerateContentConfig(response_modalities=["IMAGE"]),
    )
except errors.APIError as exc:
    print(exc.code, exc.status, exc.message)
    # e.g. 403 PERMISSION_DENIED  API key missing permission for gemini-3-pro-image
```

See [Errors](/concepts/errors#gemini-compatible-api) for the full status list.
