Nano Banana 2 Lite (Gemini 3.1 Flash Lite Image)
Generate and edit 1K images with Nano Banana 2 Lite, Google's lowest-latency image model, through one async endpoint using the generateContent request body.
Nano Banana 2 Lite is Google's Gemini 3.1 Flash Lite Image model, the low-latency, low-cost member of the family. It renders at 1K. Send Google's generateContent request body with a model field, keep the returned task ID, and check that task for the finished image. Reference images go in contents as fileData URLs.
Model IDs
| Model ID | Channel | Billing |
|---|---|---|
gemini-3.1-flash-lite-image-official | Official | Per-token rates for input, text/thinking output and image output |
Nano Banana 2 Lite is sold on token billing only. See the model page for current prices.
Quick example
curl https://api.seedrouter.ai/v1/images/generations \
-H "Authorization: Bearer $SEEDROUTER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gemini-3.1-flash-lite-image-official",
"contents": [{"parts": [{"text": "A ceramic teapot on a linen tablecloth, soft window light"}]}],
"generationConfig": {
"responseModalities": ["IMAGE"],
"imageConfig": {"aspectRatio": "16:9", "imageSize": "1K"}
}
}'Endpoint
POST https://api.seedrouter.ai/v1/images/generations| Header | Value |
|---|---|
| Authorization | Bearer YOUR_API_KEY |
| Content-Type | application/json |
The body is Google's generateContent request with one addition: model, because this endpoint carries no model in its path. The response contains a task ID, not the finished image. Keep API keys in server-side code. Calling /v1beta/models/...:generateContent directly is not supported; use this endpoint.
Parameters
| Name | Type | Required | Default | Notes |
|---|---|---|---|---|
model | string | Yes | — | The model ID above. |
contents | Content[] | Yes | — | 1–32 turns. Each has parts and an optional role (user or model); the last turn is user. |
contents[].parts[].text | string | — | — | A text part. At least one text part is required. |
contents[].parts[].fileData | object | No | — | {"mimeType": "...", "fileUri": "https://..."}; an image, video, or PDF reference. Up to 14 in total. |
systemInstruction | object | No | — | {"parts": [{"text": "..."}]}. |
safetySettings | object[] | No | — | {"category", "threshold"} pairs; see below. |
generationConfig.responseModalities | enum[] | No | text and image | ["IMAGE"] for images only, or ["TEXT", "IMAGE"]. |
generationConfig.imageConfig.aspectRatio | enum | No | Input image ratio, else 1:1 | 1:1, 1:4, 4:1, 1:8, 8:1, 2:3, 3:2, 3:4, 4:3, 4:5, 5:4, 9:16, 16:9, 21:9. |
generationConfig.imageConfig.imageSize | enum | No | 1K | 1K only. |
generationConfig.candidateCount | integer | No | 1 | Only 1. One request returns one image. |
generationConfig.temperature | number | No | Model default | 0–2. |
generationConfig.topP | number | No | Model default | 0–1. |
generationConfig.topK | integer | No | Model default | 1 or more. |
generationConfig.seed | integer | No | — | 32-bit integer. |
generationConfig.maxOutputTokens | integer | No | Model default | 1–4,096. |
generationConfig.stopSequences | string[] | No | — | Up to 5. |
generationConfig.mediaResolution | enum | No | Model default | MEDIA_RESOLUTION_LOW, MEDIA_RESOLUTION_MEDIUM, MEDIA_RESOLUTION_HIGH. Sets how many tokens input media use. |
generationConfig.thinkingConfig.includeThoughts | boolean | No | false | Return the model's thought summaries as output.thoughts. |
generationConfig.thinkingConfig.thinkingLevel | enum | No | MINIMAL | MINIMAL or HIGH. |
Safety categories: HARM_CATEGORY_HARASSMENT, HARM_CATEGORY_HATE_SPEECH, HARM_CATEGORY_SEXUALLY_EXPLICIT, HARM_CATEGORY_DANGEROUS_CONTENT. Thresholds: BLOCK_NONE, BLOCK_ONLY_HIGH, BLOCK_MEDIUM_AND_ABOVE, BLOCK_LOW_AND_ABOVE, OFF.
Unknown fields are rejected. Not yet available: Google Search grounding (tools) and cached content. inlineData is not accepted; pass media as fileData URLs.
Output size
imageSize | 1:1 output | Image tokens |
|---|---|---|
1K | 1024×1024 | 1,120 |
Other aspect ratios keep the same token count.
Modes
There is no separate mode parameter or editing endpoint.
| Operation | Parameters |
|---|---|
| Text to image | a text part |
| Edit or compose | text part + one or more fileData parts |
| Multi-turn edit | earlier user and model turns, then a new user turn (see the note below) |
To continue a conversation, rebuild the model turn from the previous task's output.parts, in order: a text part becomes {"text": ..., "thoughtSignature": ...} and an image part becomes {"fileData": {"mimeType": "image/<output_format>", "fileUri": <data[image].url>}, "thoughtSignature": ...}. Keep each thoughtSignature exactly as returned: it is the URL of the signature we stored for you (a 4K image's signature is several megabytes), and we restore it before the request reaches the model. Only signatures from your own task results are accepted.
Edit with a reference image
curl https://api.seedrouter.ai/v1/images/generations \
-H "Authorization: Bearer $SEEDROUTER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gemini-3.1-flash-lite-image-official",
"contents": [{
"role": "user",
"parts": [
{"text": "Turn this photo into a watercolor painting. Keep the composition."},
{"fileData": {"mimeType": "image/jpeg", "fileUri": "https://example.com/photo.jpg"}}
]
}]
}'Replace the example URL with your own accessible image.
Media inputs
This API accepts URL references only. Base64 inlineData, data: URLs, and multipart uploads are not accepted. The Playground uploads selected files to storage before submitting their URLs.
References must be public HTTP(S) URLs, each smaller than 50 MB and 100 MB in total: images (image/png, image/jpeg, image/webp, image/heic, image/heif), videos (video/mp4, video/mpeg, video/mov, video/avi, video/x-flv, video/mpg, video/webm, video/wmv, video/3gpp), or PDF documents (application/pdf). mimeType must match the file. URLs are fetched during processing; an inaccessible image fails the task, and a failed task is not charged.
Pricing dimensions
Check the model pricing section for current rates. gemini-3.1-flash-lite-image-official charges by usage: input tokens (text and reference images), text and thinking output tokens, and image output tokens, each at its own rate. Image output is the main factor; every image is 1K.
View final charges in your account usage history. Failed tasks are not charged.
Output schema
Submission returns a task reference:
{
"id": "task_...",
"model": "gemini-3.1-flash-lite-image-official",
"status": "processing",
"created_at": 1790310979
}Poll the task
curl https://api.seedrouter.ai/v1/tasks/YOUR_TASK_ID \
-H "Authorization: Bearer $SEEDROUTER_API_KEY"Poll every few seconds until status is completed or failed. A network timeout while polling does not mean generation failed: keep the task ID and resume checking it. Do not create another task to check progress.
Complete polling example
Run this after the Python submission example above.
import time
deadline = time.monotonic() + 600
while time.monotonic() < deadline:
result = requests.get(
f"https://api.seedrouter.ai/v1/tasks/{task_id}",
headers={"Authorization": f"Bearer {os.environ['SEEDROUTER_API_KEY']}"},
timeout=30,
)
result.raise_for_status()
task = result.json()
if task["status"] == "completed":
for image in task["output"]["data"]:
print(image["url"])
break
if task["status"] == "failed":
raise RuntimeError(task["error"]["message"])
time.sleep(3)
else:
raise TimeoutError(f"Still waiting. Resume polling task {task_id}.")Completed task
{
"id": "task_...",
"model": "gemini-3.1-flash-lite-image-official",
"status": "completed",
"created_at": 1790310979,
"finished_at": 1790311001,
"output": {
"created": 1790310999,
"data": [{"url": "https://static.seedrouter.ai/media/tasks/task_example/0.jpg"}],
"output_format": "jpeg",
"usage": {
"input_tokens": 27,
"output_tokens": 1518,
"total_tokens": 1545,
"output_tokens_details": {"image_tokens": 1120, "text_tokens": 398, "reasoning_tokens": 0}
}
}
}| Field | Meaning |
|---|---|
id | Keep this ID for subsequent queries. |
status | processing, completed, or failed. |
created_at, finished_at | Unix timestamps in seconds. |
output.data[].url | The generated image URL. |
output.text | Text the model returned alongside the image, when responseModalities includes TEXT. Thoughts are not included. |
output.thoughts | The model's thought summaries, when includeThoughts is true. Interim images the model draws while thinking are not delivered. |
output.output_format | Actual image format. |
output.parts | The final response parts in order, for multi-turn editing: {"text", "thoughtSignature"} or {"image": <index into data>, "thoughtSignature"}. thoughtSignature is a URL; send it back unchanged. |
output.usage | Token usage. output_tokens counts text, thinking, and image output; output_tokens_details.image_tokens is the image part. |
error | Structured error on a failed task. |
Streaming (streamGenerateContent) is not supported; results are delivered through the task.
Errors
Requests rejected before a task is created return an HTTP error with an error object. A task that fails after acceptance returns HTTP 200 when queried, with status: "failed" and an error object. An image withheld by the model's safety filters fails with content_policy_violation; a response with no image fails with no_output.
See the shared error catalog for codes, HTTP statuses, and retry guidance.
{
"id": "task_...",
"status": "failed",
"error": {
"code": 60001,
"message": "The request was rejected by the content policy. Please revise the prompt or input images."
}
}If submission itself times out, check your task history before submitting again: the first request may have been accepted.
Tips
- Describe subject, setting, lighting, and style in full sentences.
- For an edit, say what should change and what must stay the same.
- Choose Nano Banana 2 or Nano Banana Pro when you need 2K or 4K output.
- Save returned images to your own storage when you need a durable copy.
