Gemini Native (Image)
curl --request POST \
--url https://api.mixroute.ai/v1/models/{model}:generateContentimport requests
url = "https://api.mixroute.ai/v1/models/{model}:generateContent"
response = requests.post(url)
print(response.text)const options = {method: 'POST'};
fetch('https://api.mixroute.ai/v1/models/{model}:generateContent', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.mixroute.ai/v1/models/{model}:generateContent",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.mixroute.ai/v1/models/{model}:generateContent"
req, _ := http.NewRequest("POST", url, nil)
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.mixroute.ai/v1/models/{model}:generateContent")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.mixroute.ai/v1/models/{model}:generateContent")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
response = http.request(request)
puts response.read_bodyImage Series
Gemini Native (Image)
Native Gemini image generation/editing fields and model-specific limits.
Gemini Native (Image)
curl --request POST \
--url https://api.mixroute.ai/v1/models/{model}:generateContentimport requests
url = "https://api.mixroute.ai/v1/models/{model}:generateContent"
response = requests.post(url)
print(response.text)const options = {method: 'POST'};
fetch('https://api.mixroute.ai/v1/models/{model}:generateContent', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.mixroute.ai/v1/models/{model}:generateContent",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.mixroute.ai/v1/models/{model}:generateContent"
req, _ := http.NewRequest("POST", url, nil)
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.mixroute.ai/v1/models/{model}:generateContent")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.mixroute.ai/v1/models/{model}:generateContent")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
response = http.request(request)
puts response.read_bodyGenerate and edit images with Gemini using native Content parts and generationConfig settings.
POST https://api.mixroute.ai/v1/models/{model}:generateContent
Models
| Model ID | Capabilities and Limits |
|---|---|
gemini-3.1-flash-image | Nano Banana 2; 512, 1K, 2K, 4K output; MINIMAL/HIGH thinking. |
gemini-3.1-flash-image-preview | Nano Banana 2; 512, 1K, 2K, 4K output; MINIMAL/HIGH thinking. |
gemini-3-pro-image | Nano Banana Pro; 1K, 2K, 4K output and image/text reasoning. |
gemini-3-pro-image-preview | Nano Banana Pro; 1K, 2K, 4K output and image/text reasoning. |
gemini-3.1-flash-lite-image | Nano Banana 2 Lite; 1K output only; no Google Search grounding. |
gemini-2.5-flash-image | Original Nano Banana; approximately 1K output. Omit imageSize. |
Request Parameters
| Field | Type | Required | Description |
|---|---|---|---|
model (URL path) | string | Yes | Model ID in the endpoint path, not an extra JSON body field. |
contents | object[] | Yes | Conversation turns containing text and optional image inputs. |
contents[].role | string | No | user or model. Use the model role when preserving previous model output in a conversation. |
contents[].parts | object[] | Yes | Content parts. Text instructions and image parts can be combined for editing. |
contents[].parts[].text | string | Conditional | Text prompt or edit instruction. |
contents[].parts[].inlineData | object | Conditional | Inline image bytes: mimeType plus raw Base64 data. Do not include a data-URI prefix in data. |
contents[].parts[].inlineData.mimeType | string | Conditional | Image MIME type, such as image/png, image/jpeg, or image/webp. |
contents[].parts[].inlineData.data | string | Conditional | Base64-encoded image bytes. |
contents[].parts[].fileData | object | No | Native file reference with fileUri and mimeType. The file must be accessible to the route’s upstream account. |
contents[].parts[].thoughtSignature | string | No | Opaque signature returned by the model. Preserve it exactly when returning previous model content in a later turn; never invent or modify it. |
systemInstruction | object | No | Native Content object for system instructions, typically using parts[].text. |
generationConfig | object | No | Native generation settings. |
generationConfig.responseModalities | string[] | No | Include IMAGE to request image output, optionally with TEXT. Example: [“TEXT”, “IMAGE”]. |
generationConfig.imageConfig.aspectRatio | string | No | Output aspect ratio. Without it, the model follows the reference image ratio or chooses a square. See model limits below. |
generationConfig.imageConfig.imageSize | string | No | Default 1K on models supporting this setting. Use 512/1K/2K/4K for 3.1 Flash Image, 1K/2K/4K for Pro, and 1K only for Lite. Omit for 2.5 Flash Image. |
generationConfig.thinkingConfig.thinkingLevel | string | No | 3.1 Flash Image and Lite support MINIMAL or HIGH, default MINIMAL. Do not apply these levels to other models without their support. |
generationConfig.thinkingConfig.includeThoughts | boolean | No | Whether to include supported thought summaries/parts in the response. Final-image handling should skip parts marked thought=true. |
generationConfig.maxOutputTokens | integer | No | Output budget shared by text and image output. A very small budget can prevent a complete image response; respect the model limit. |
tools | object[] | No | Native tools. 3.1 Flash Image and Pro can use googleSearch grounding; Lite and 2.5 Flash Image do not support this image-search-grounding workflow. |
safetySettings | object[] | No | Native safety settings with category and threshold, subject to model and account policy. Do not repeat the same category. |
Model Constraints
1:1, 2:3, 3:2, 3:4, 4:3, 4:5, 5:4, 9:16, 16:9, 21:9
Gemini 3.1 Flash Image additionally supports 1:4, 4:1, 1:8, and 8:1. Only use sizes/aspect ratios supported by the selected model. Gemini 3 image models support up to 14 reference images with model-specific subject limits; Lite is optimized for lightweight workflows. The image API is not controlled by an OpenAI n or size field.
Examples
Use your MixRoute key in theMIXROUTE_API_KEY environment variable. Requests use Authorization: Bearer .... Replace source-image placeholders with accessible images or local files before editing.
curl --request POST "https://api.mixroute.ai/v1/models/gemini-3.1-flash-image:generateContent" \
--header "Authorization: Bearer $MIXROUTE_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"contents": [
{
"role": "user",
"parts": [
{
"text": "A clean product photograph of a red ceramic mug on a white background."
}
]
}
],
"generationConfig": {
"responseModalities": [
"TEXT",
"IMAGE"
],
"imageConfig": {
"aspectRatio": "1:1",
"imageSize": "1K"
}
}
}'
Python
import json
import os
import requests
payload = json.loads(r'''
{
"contents": [
{
"role": "user",
"parts": [
{
"text": "A clean product photograph of a red ceramic mug on a white background."
}
]
}
],
"generationConfig": {
"responseModalities": [
"TEXT",
"IMAGE"
],
"imageConfig": {
"aspectRatio": "1:1",
"imageSize": "1K"
}
}
}
''')
response = requests.post(
"https://api.mixroute.ai/v1/models/gemini-3.1-flash-image:generateContent",
headers={"Authorization": "Bearer " + os.environ["MIXROUTE_API_KEY"]},
json=payload,
timeout=180,
)
response.raise_for_status()
result = response.json()
import base64
from pathlib import Path
image_index = 0
for candidate in result.get("candidates", []):
for part in candidate.get("content", {}).get("parts", []):
if part.get("thought"):
continue
inline = part.get("inlineData")
if inline and inline.get("data"):
extension = {"image/png": "png", "image/jpeg": "jpg", "image/webp": "webp"}.get(inline.get("mimeType"), "bin")
Path(f"image_{image_index}.{extension}").write_bytes(base64.b64decode(inline["data"]))
image_index += 1
elif "text" in part:
print(part["text"])
Image Editing and Conversation
For editing, add an inlineData image part to the user turn alongside the text instruction. For a subsequent edit, append the complete prior candidate.content object to contents and then add the next user turn; this retains native image data and thought signatures. Do not replace the model history with text alone.{
"contents": [
{
"role": "user",
"parts": [
{
"text": "Make the mug blue while preserving its shape, lighting, and background."
},
{
"inlineData": {
"mimeType": "image/png",
"data": "BASE64_IMAGE_DATA"
}
}
]
}
],
"generationConfig": {
"responseModalities": [
"TEXT",
"IMAGE"
],
"imageConfig": {
"aspectRatio": "1:1",
"imageSize": "1K"
}
}
}