Nano Banana (Native Gemini Image Generation) Integration
This guide explains how to generate images with Nano Banana 2 and Nano Banana Pro through Google's native Gemini protocol. See the available model list for the current Gemini catalog.
Product names and API model IDs
| Product name | Recommended API model ID | Compatibility / preview alias |
|---|---|---|
| Nano Banana 2 | gemini-3.1-flash-image | gemini-3.1-flash-image-preview |
| Nano Banana Pro | gemini-3-pro-image | gemini-3-pro-image-preview |
- Prefer the recommended ID for new integrations.
- Compatibility and preview aliases keep existing integrations working, but their availability and behavior may change with upstream updates.
- The request URL must contain one of the
gemini-*IDs in the table.Nano Banana 2andNano Banana Proare product names, not native API model IDs. - Real-time availability for an API key is determined by the Available Models API.
Use the native Google protocol
Gemini image models (IDs containing -image) support image generation only through Google's native :generateContent endpoint. Do not use OpenAI /v1/chat/completions: it may return HTTP 200 and appear successful while silently dropping the image, and output tokens are still billed. The current model catalog contains six Gemini image model IDs: gemini-2.5-flash-image, gemini-3-pro-image, gemini-3-pro-image-preview, gemini-3.1-flash-image, gemini-3.1-flash-image-preview, and gemini-3.1-flash-lite-image; all six require the native Google protocol described on this page.
Prerequisites
Get an API key for a Gemini group from the console and select the API BaseURL for your region. The BaseURL must not include /v1beta:
export API_BASE="https://<YOUR_API_BASE_URL>"
export API_KEY="<YOUR_GEMINI_API_KEY>"
export MODEL="gemini-3.1-flash-image"Use x-goog-api-key for native Gemini requests. The platform also accepts Authorization: Bearer <API key>, but a request only needs one authentication method.
The API key must belong to a Gemini group. If the console value already includes
/v1beta, remove that suffix before assigning it toAPI_BASEto avoid duplicating the path.
Synchronous image generation
generateContent keeps the connection open until generation completes or fails:
POST /v1beta/models/{model}:generateContentThe following Nano Banana 2 example requests one 4K, 16:9 image:
curl --request POST \
"$API_BASE/v1beta/models/$MODEL:generateContent" \
--header "x-goog-api-key: $API_KEY" \
--header "Content-Type: application/json" \
--data '{
"contents": [
{
"role": "user",
"parts": [
{
"text": "Hong Kong harbour in winter, morning mist, ferries and the distant city skyline, cinematic photorealism"
}
]
}
],
"generationConfig": {
"responseModalities": ["TEXT", "IMAGE"],
"imageConfig": {
"aspectRatio": "16:9",
"imageSize": "4K"
}
}
}' \
--output response.jsonTo use Nano Banana Pro, change only the model ID:
export MODEL="gemini-3-pro-image"Common imageConfig fields:
| Field | Example | Description |
|---|---|---|
aspectRatio | "16:9" | Common values include 1:1, 16:9, 9:16, 4:3, and 3:4 |
imageSize | "4K" | Supports 1K, 2K, and 4K; use an uppercase K |
If you only need the image, set responseModalities to ["IMAGE"].
Read and save the image
The generated image is returned as Base64 at:
candidates[].content.parts[].inlineData.dataThe same part contains the image MIME type in inlineData.mimeType. Extract the first image with jq:
jq -r '
.candidates[].content.parts[]
| select(.inlineData.data != null)
| .inlineData.data
' response.json > image.b64Decode it on macOS:
base64 -D image.b64 > nano-banana.pngDecode it on Linux:
base64 --decode image.b64 > nano-banana.pngDo not validate success from the HTTP status alone. A successful image request must contain at least one inlineData.data part. If it does not, treat the request as failed and inspect the model ID, protocol, and response body.
Synchronous, streaming, and asynchronous boundaries
| Mode | Endpoint | Capability |
|---|---|---|
| Synchronous | :generateContent | Supported and recommended for one-off image generation |
| Streaming | :streamGenerateContent?alt=sse | Supported through SSE; it still keeps one request open |
| Background async task | No native endpoint | No GPT Image-style submit-and-poll workflow with a task ID |
Streaming is not a background asynchronous task. If the client disconnects, it cannot resume or poll that request with a task ID. Native Gemini image generation has neither /v1/images/generations/async nor a general :generateContent/async endpoint. If your application needs a non-blocking workflow, run the synchronous request from your own job queue and persist the result.
The platform also has a separate /v1/images/batches asynchronous batch wrapper. It is not native Google generateContent, and that route is not currently enabled on the public API regions, so this page does not provide a callable example for it.
Streaming request example
Use the following endpoint if your client needs SSE events:
curl --no-buffer --request POST \
"$API_BASE/v1beta/models/$MODEL:streamGenerateContent?alt=sse" \
--header "x-goog-api-key: $API_KEY" \
--header "Content-Type: application/json" \
--data '{
"contents": [
{
"role": "user",
"parts": [{"text": "Hong Kong harbour in winter, cinematic photorealism"}]
}
],
"generationConfig": {
"responseModalities": ["TEXT", "IMAGE"],
"imageConfig": {
"aspectRatio": "16:9",
"imageSize": "4K"
}
}
}'Image data is still located under candidates[].content.parts[].inlineData in the JSON carried by the SSE events.
Troubleshooting
- HTTP 200 but no image: Make sure you called
/v1beta/models/{model}:generateContent, not/v1/chat/completions, and thatresponseModalitiescontainsIMAGE. - Group mismatch: Create or use an API key assigned to a Gemini group. Keys for other provider groups cannot call native Gemini endpoints.
- 404 path error: Make sure
API_BASEdoes not end in/v1or/v1beta, and verify that the final URL contains/v1betaonly once. - Long-connection timeout: Increase the read timeout in your client and reverse proxy, or wrap the synchronous call in your own job queue. Do not switch to OpenAI
chat/completions. - Model unavailable: Check the available model list or the Available Models API for the API key's current access.