| name | openrouter-image-generation |
| description | Fix for OpenRouter image generation response parsing. Use when: (1) using OpenRouter API
with image generation models like google/gemini-2.5-flash-image, (2) response doesn't
contain expected image data, (3) looking for base64 image in wrong location. Images are
returned in message.images array, not in standard OpenAI format. Covers correct endpoint,
response parsing, and base64 extraction.
|
| author | Claude Code |
| version | 1.0.0 |
| date | "2026-01-23T00:00:00.000Z" |
OpenRouter Image Generation Response Format
Problem
When using OpenRouter's image generation models (like google/gemini-2.5-flash-image),
the response format differs from expectations. Images are not returned in the standard
location, causing parsing failures.
Context / Trigger Conditions
- Using OpenRouter API (
https://openrouter.ai/api/v1/chat/completions) for image generation
- Model is an image generation model (e.g.,
google/gemini-2.5-flash-image)
- Response returns 200 OK but no image found in expected location
- Looking for image URL or base64 data and not finding it
Solution
1. Use the Chat Completions Endpoint (NOT /images/generations)
response = requests.post(
"https://openrouter.ai/api/v1/chat/completions",
headers={
"Authorization": f"Bearer {OPENROUTER_API_KEY}",
"Content-Type": "application/json",
},
json={
"model": "google/gemini-2.5-flash-image",
"messages": [{"role": "user", "content": "Generate a pixel art sword"}],
},
)
2. Extract Image from Correct Location
Images are returned in choices[0].message.images array, NOT in a standard image field:
result = response.json()
message = result.get("choices", [{}])[0].get("message", {})
images = message.get("images", [])
if images:
img_url = images[0].get("image_url", {}).get("url", "")
if img_url.startswith("data:image"):
b64_data = img_url.split(",")[1]
img_bytes = base64.b64decode(b64_data)
3. Complete Response Structure
{
"choices": [{
"message": {
"content": "Here is your image...",
"images": [{
"image_url": {
"url": "data:image/png;base64,iVBORw0KGgo..."
}
}]
}
}]
}
Verification
- Check that
response.json()["choices"][0]["message"]["images"] exists and has items
- Verify the
image_url.url starts with data:image
- Decode base64 and write to file - should produce valid image
Example
import requests
import base64
def generate_image(prompt: str, api_key: str) -> bytes:
response = requests.post(
"https://openrouter.ai/api/v1/chat/completions",
headers={
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json",
},
json={
"model": "google/gemini-2.5-flash-image",
"messages": [{"role": "user", "content": prompt}],
},
timeout=120,
)
result = response.json()
images = result["choices"][0]["message"].get("images", [])
if not images:
raise ValueError("No image in response")
img_url = images[0]["image_url"]["url"]
b64_data = img_url.split(",")[1]
return base64.b64decode(b64_data)
img_bytes = generate_image("A pixel art treasure chest", api_key)
with open("treasure.png", "wb") as f:
f.write(img_bytes)
Notes
- All models generate at fixed sizes (typically 1024x1024) regardless of requested size
- The
/images/generations endpoint may return 404 for some models - use chat/completions instead
- Cost-effective models include
google/gemini-2.5-flash-image for pixel art generation
- Include style instructions in the prompt for consistent results (e.g., "16-bit pixel art, SNES style")
References
- OpenRouter API Documentation: https://openrouter.ai/docs
- Available image models can be queried via:
GET https://openrouter.ai/api/v1/models