Image generation

Generate and edit images with one request. The endpoint has the shape of the OpenAI images API, so an unchanged OpenAI client works. Only a deployment that is registered to make images can win the job.

Quickstart

curl https://router.inference.ai.exchange/v1/images/generations \
  -H "Authorization: Bearer sk-liquid-..." \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gemini-2.5-flash-image",
    "prompt": "a cat on a bicycle",
    "n": 2,
    "size": "1024x1024"
  }'
from openai import OpenAI

client = OpenAI(base_url="https://router.inference.ai.exchange/v1", api_key="sk-liquid-...")

result = client.images.generate(
    model="gemini-2.5-flash-image",
    prompt="a cat on a bicycle",
    n=2,
    size="1024x1024",
)

Each image comes back as b64_json or url. The exchange block of the answer holds the receipt. See Response.

Examples

Operators of the exchange made example images with each model. The page of a model in the console lists them. The app shows two here, each with its model and its prompt.

Find a model

A control works only when an offer for the model declares it. Read what a model supports before you send a control.

Source Use it for
GET /v1/models?kind=image One card for each model: parameters, image_sizes and pricing.
GET /v1/exchange/models?kind=image The market view, with no key: sizes, formats, response_formats and rate_per_image_usd.
The model page in the console The same data, with example images and a Playground.

On the card of an image model:

A preset of the image kind buys every listed model of its kind. If a request sets a control that no offer declared, the answer is 400 unsupported_parameter and param names the control or its feature, such as image.seed. The exchange holds nothing and sends nothing.

How it works

  1. Send the request. The exchange picks the offers that can serve it.
  2. The exchange fixes the price cap. The price is for one image, so the cap is exactly the charge.
  3. The provider makes the images. The exchange dispatches the size that it resolved.
  4. You get the answer, or events if you set stream. The charge is for the images that the provider returned.

Size, tier and shape

Send size when you know the pixel size. Send resolution or aspect_ratio when you do not. The exchange then picks a pixel size that an offer declared. It buys, prices and dispatches that size, as if you had sent it as size.

{ "model": "<model>", "prompt": "a cat on a bicycle", "resolution": "2K", "aspect_ratio": "16:9" }
Tier Sizes that have it
512 512x512
768 1024x576
1K 1024x1024, 1536x1024, 1024x1536
1.5K 1920x1080
2K 2048x2048, 3840x2160
4K 4096x4096

Controls

seed, background, output_compression and stream are offer features: image.seed, image.background, image.output_compression and image.stream. An offer wins a request that sets one only when it declared the feature. An offer that did not declare it cannot win, because it would ignore the control and still charge for the image.

background: "auto" and stream: false ask for nothing. Any offer can win them.

Seed

seed makes a picture repeatable on a best-effort basis. An upstream can change its model.

{ "model": "<model>", "prompt": "a cat on a bicycle", "seed": 42 }

Background

background is transparent, opaque or auto. transparent needs output_format png or webp, or no output_format. With jpeg the answer is 400 conflicting_parameters.

{ "model": "<model>", "prompt": "a logo", "output_format": "png", "background": "transparent" }

Compression

output_compression is a whole number from 0 to 100. It applies to jpeg and webp. With png the answer is 400 conflicting_parameters.

{ "model": "<model>", "prompt": "a cat", "output_format": "webp", "output_compression": 80 }

Quality

An offer can list the quality names that it takes. If the offers of a model list any, the card has a quality key in parameters, and an offer that omits your name cannot win. An offer that lists none states nothing, so it can win and its provider decides. A provider that does not take the name fails the job before it renders, so send quality only when the model lists it.

Reference images

Send images in input_references to start from a picture. See Reference inputs. POST /v1/images/edits is the same purchase for the OpenAI SDK. It needs at least one reference image, takes the files in image, and refuses a mask.

Stream

Send stream: true to get the answer as server-sent events. The content type is text/event-stream. The request must ask for one image: stream with n above 1 gets 400 conflicting_parameters.

curl -N https://router.inference.ai.exchange/v1/images/generations \
  -H "Authorization: Bearer sk-liquid-..." \
  -H "Content-Type: application/json" \
  -d '{"model": "<model>", "prompt": "a cat on a bicycle", "stream": true}'
event: image_generation.partial_image
data: {"type":"image_generation.partial_image","partial_image_index":0,"b64_json":"iVBOR…","media_type":"image/png"}

event: image_generation.completed
data: {"type":"image_generation.completed","b64_json":"iVBOR…","media_type":"image/png","exchange":{"...":"..."}}
Event Fields When
image_generation.partial_image partial_image_index, b64_json, media_type Once for each draft. A provider sends at most three.
image_generation.completed b64_json or url, media_type, revised_prompt if any, exchange Once, for the final image.

Response

{
  "created": 1760000000,
  "data": [{ "b64_json": "iVBOR…", "media_type": "image/png" }],
  "exchange": { "...": "..." }
}

Billing

The price is for one image, so the cap that the exchange fixes is exactly the charge. The price of the size and the quality that the request names sets the charge. An image offer priced in tokens is held to the charge of one image at its output token bound.

exchange.limits.price.unit_usd sets the highest price for one image. See Purchasing rules and Modalities.

Images in a chat answer

Some chat models draw in their answer. Send modalities with image to POST /v1/chat/completions.

curl https://router.inference.ai.exchange/v1/chat/completions \
  -H "Authorization: Bearer sk-liquid-..." \
  -H "Content-Type: application/json" \
  -d '{
    "model": "<a model that draws in chat>",
    "modalities": ["image", "text"],
    "messages": [{ "role": "user", "content": "a cat on a bicycle" }]
  }'

Each image is in choices[0].message.images. The url of an image is a data: URL when the provider returned bytes. It is a link when the provider returned a link. The exchange does not change the form.

Only an offer that declared image output (output.image) can win the job. If no offer did, the exchange refuses the request with unsupported_parameter before the auction. It does not send you a text answer.

Image config

Send image_config to ask for a size. It needs image in modalities.

{
  "model": "<a model that draws in chat>",
  "modalities": ["image", "text"],
  "image_config": { "resolution": "2K", "aspect_ratio": "16:9" },
  "messages": [{ "role": "user", "content": "a cat on a bicycle" }]
}
Key Value
size <width>x<height>, or auto.
resolution or image_size A tier: 512, 768, 1K, 1.5K, 2K or 4K.
aspect_ratio <width>:<height>, or auto.
quality A quality name. It goes to the upstream and is not matched.

Cost and limits in a chat answer

Request parameters

Field Type Required Description
model string Yes The model to buy, or a preset of the image kind.
prompt string Yes The text that describes the image. At most 32,000 characters.
input_references array No Reference inputs of any kind, in one list. See Reference inputs.
n integer No How many images, from 1 to 10. The default is 1.
size string No A pixel size such as 1024x1024, or auto.
resolution string No A size tier: 512, 768, 1K, 1.5K, 2K or 4K.
aspect_ratio string No auto, or a shape such as 16:9.
output_format string No png, jpeg or webp.
quality string No A quality name that the model lists in parameters.
background string No transparent, opaque or auto.
output_compression integer No The compression of a jpeg or webp image, from 0 to 100.
seed integer No A number that makes the picture repeatable.
stream boolean No true sends the answer as events.
response_format string No url or b64_json. If you omit it, any offer can answer.
exchange object No Purchasing rules, such as cap_usd. See Purchasing rules.

A request that sends size, output_format or quality goes only to offers that serve that value, so it does not fail after the choice. If you omit size, the provider uses its default, and every offer for the model can answer.

Errors

Error Cause Fix
400 unsupported_model You named a router model that ranks by price. Name an image model, or an Auto router model.
400 unsupported_rule A rule that limits a price or a speed in tokens. Use exchange.limits.price.unit_usd and cap_usd.
400 unsupported_parameter No offer serves your size, resolution, aspect_ratio or output_format, or none declared a control. param names the field or feature. Omit it, or read image_sizes and parameters on the model card.
400 conflicting_parameters size has another tier or shape, background transparent with jpeg, output_compression with png, or stream with n above 1. Send one of the two fields, or change the other.
400 No offer takes all of your references. Read eligibility.excluded.

See Errors for each code and exclusion reason.

Next steps