Multimodal
Image generation
One endpoint for both text-to-image and image-to-image —
POST /v1/images, matching
OpenRouter's own /api/v1/images contract
exactly (confirmed against their real OpenAPI spec — there's no separate "generate" vs. "edit" endpoint on
their side either). Image-to-image happens on this same endpoint via
input_references, not a separate
multipart upload. Billed per image, with a real
usage block — including
cost — inside the JSON response body,
not just a response header.
resp = httpx.post(
"https://llmrouter.sh/v1/images",
headers={"Authorization": f"Bearer {API_KEY}"},
json={
"model": "gpt-image-1",
"prompt": "a red panda astronaut floating in space",
"aspect_ratio": "16:9",
"resolution": "2K",
},
).json()
print(resp["data"][0]["b64_json"][:50], resp["usage"]["cost"])
Image-to-image: pass one or more reference images via input_references (URL
or base64 data URL, same two shapes as image input)
instead of uploading a file:
resp = httpx.post(
"https://llmrouter.sh/v1/images",
headers={"Authorization": f"Bearer {API_KEY}"},
json={
"model": "gemini-2.5-flash-image",
"prompt": "make this scene look like a watercolor painting",
"input_references": [
{"type": "image_url", "image_url": {"url": "https://example.com/photo.jpg"}}
],
},
).json()
Every model listed under Which models below,
plus the chat-native image models
(gemini-2.5-flash-image,
gemini-3-pro-image-preview,
gemini-3.1-flash-image-preview) work here —
one catalog, one endpoint, whichever mechanism each model actually uses under the hood. Other parameters:
size (an explicit
"WxH" string overrides
resolution/aspect_ratio when
given), quality,
output_format,
background, and
output_compression (all OpenAI-models-only —
ignored elsewhere, same as OpenRouter's own "ignored by providers lacking X control" behavior),
n for multiple images per call.
stream: true is not supported —
rejected with a 400, not silently ignored. Non-square aspect_ratio on
dall-e-2 is clamped to square (it only has
one size tier per axis); DeepInfra/SiliconFlow models don't honor
resolution/aspect_ratio yet.
Which models
Seven models across three providers, served direct (no cross-provider failover for this endpoint):
dall-e-3OpenAIdefault for model:"auto"dall-e-2OpenAI—gpt-image-2OpenAIlatest OpenAI model; generation + edits, priced per tokenimagen-4.0Google—imagen-4.0-fastGoogle—imagen-4.0-ultraGoogle—qwen-image-2.0Qwen—qwen-image-2.0-proQwen—
size and
quality are only forwarded for OpenAI
models — Imagen and Qwen don't take them the same way and ignore/reject them.
Image output in chat completions
A second way to get an image back: pass modalities: ["image", "text"] to
POST /v1/chat/completions itself — the
same wire contract OpenRouter uses. The generated image comes back on the assistant message as
message.images[0].image_url.url (a base64
data URL), alongside whatever text the model also returned.
resp = client.chat.completions.create(
model="gemini-2.5-flash-image",
messages=[{"role": "user", "content": "Generate a beautiful sunset over mountains"}],
modalities=["image", "text"],
)
message = resp.choices[0].message
for image in (message.images or []):
image_url = image["image_url"]["url"] # base64 data URL
print(f"Generated image: {image_url[:50]}...")
This works with an uploaded image too — combine an image_url
content part (see Image understanding) in the
same request with modalities: ["image", "text"] to
send an image in and get an edited/re-imagined image back through the same endpoint.
Three models today, all Google:
gemini-2.5-flash-imagereturns PNGgemini-3-pro-image-previewreturns JPEG; highest quality, highest costgemini-3.1-flash-image-previewreturns JPEG
model: "auto" is not supported for this —
pass the model explicitly. Billed per request off the response's own
usage.completion_tokens_details split: image
tokens (and, on gemini-3-pro-image-preview,
reasoning tokens) bill at a materially higher per-token rate than plain text tokens (this is the provider's own
pricing, not a platform markup), so cost varies with image size/complexity rather than being a flat per-call
price like /v1/images above.
A vague, templated prompt (e.g. "a tiny icon of a red circle") can trigger Gemini's own recitation safety
filter and come back with no image at all — a descriptive, original prompt avoids this.
Grok, DeepSeek, and Meta's muse-spark-1.1 don't
support this yet — each was tested directly, not assumed: Grok and OpenAI's gpt-5.1/gpt-5.2 reject
the modalities parameter outright,
DeepSeek silently ignores it and returns text only, and Muse Spark's own API rejects
"image" as an invalid modality
value (it supports image input, not output). We'll add a model here as soon as one of these — or
another provider — has a real, verified image-output path.
Not yet supported
Generating multiple unprompted variations of an existing image (no edit instruction, just "more like this")
has no equivalent here. Mask-based inpainting via input_references —
restricting an edit to one region of the image — isn't supported either, only whole-image edits.
stream: true is rejected outright (see
above). Chat-native image output is scoped to three Google models for now.