Gemini Native (Image, Streaming)
curl --request POST \
--url https://api.mixroute.ai/v1/models/{model}:streamGenerateContentimport requests
url = "https://api.mixroute.ai/v1/models/{model}:streamGenerateContent"
response = requests.post(url)
print(response.text)const options = {method: 'POST'};
fetch('https://api.mixroute.ai/v1/models/{model}:streamGenerateContent', 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}:streamGenerateContent",
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}:streamGenerateContent"
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}:streamGenerateContent")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.mixroute.ai/v1/models/{model}:streamGenerateContent")
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, Streaming)
Native Gemini image streaming requests and response handling.
Gemini Native (Image, Streaming)
curl --request POST \
--url https://api.mixroute.ai/v1/models/{model}:streamGenerateContentimport requests
url = "https://api.mixroute.ai/v1/models/{model}:streamGenerateContent"
response = requests.post(url)
print(response.text)const options = {method: 'POST'};
fetch('https://api.mixroute.ai/v1/models/{model}:streamGenerateContent', 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}:streamGenerateContent",
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}:streamGenerateContent"
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}:streamGenerateContent")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.mixroute.ai/v1/models/{model}:streamGenerateContent")
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_bodyStream Gemini image-generation responses using the native streamGenerateContent endpoint. Request fields are the same as generateContent.
The request body uses the same fields and model restrictions as Gemini image generation. Use
POST https://api.mixroute.ai/v1/models/{model}:streamGenerateContent?alt=sse
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. |
alt=sse in the query string; do not add a body stream parameter.
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 --no-buffer --request POST "https://api.mixroute.ai/v1/models/gemini-3.1-flash-image:streamGenerateContent?alt=sse" \
--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 base64
import json
import os
from pathlib import Path
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"
}
}
}
''')
def events(lines):
data = []
for line in lines:
if line == "":
if data:
yield "\n".join(data)
data.clear()
elif line.startswith("data:"):
value = line[5:]
data.append(value[1:] if value.startswith(" ") else value)
if data:
yield "\n".join(data)
url = "https://api.mixroute.ai/v1/models/gemini-3.1-flash-image:streamGenerateContent?alt=sse"
image_index = 0
with requests.post(url, headers={"Authorization": "Bearer " + os.environ["MIXROUTE_API_KEY"]}, json=payload, stream=True, timeout=(30, 180)) as response:
response.raise_for_status()
response.encoding = "utf-8"
for data in events(response.iter_lines(decode_unicode=True)):
if not data.strip():
continue
if data.strip() == "[DONE]":
break
chunk = json.loads(data)
if "error" in chunk:
raise RuntimeError(chunk["error"])
for candidate in chunk.get("candidates", []):
for part in candidate.get("content", {}).get("parts", []):
if part.get("thought"):
continue
if "inlineData" in part:
inline = part["inlineData"]
if 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"], validate=True))
image_index += 1
elif "text" in part:
print(part["text"], end="")