Create images

Generates images from a text prompt, optionally with reference images for image-to-image. It is compatible with images.generate in the OpenAI Images API: the official OpenAI SDKs work once you set the Base URL to https://api.lyrouter.com/v1, and the image comes back in the same response, with no polling. Three families are available: Seedream 5.0, GPT-Image and Gemini Image. Parameters and the returned format differ by family; see the per-model sections below.

POST/v1/images/generations

Authentication

Send your API key in a request header:

Authorization: Bearer <API Key>

Bearer is case-sensitive. You can use x-api-key: <API Key> instead; when both are present, only Authorization is read. Create API keys on the workspace's API Keys page. Your API key is used only to authenticate with LYRouter and is never forwarded to the upstream provider. See Base URLs and authentication.

Headers

Header Required Description
Content-Type Yes application/json
X-Gateway-Strict-Parameters No When set to true (lowercase only), a request containing any parameter the gateway would drop returns 400 unsupported_parameters immediately, without calling the upstream and without charge. For which parameters are dropped, see "How each model is handled" below

Request body

The parameters shared by all models are listed below; whether each one takes effect for a given family is described in the model sections that follow.

Parameter Type Required Description
model string Yes Image model ID, such as bytedance/doubao-seedream-5.0-lite. Only concrete model IDs work: a virtual model @vmodel/<name> or lyrouter/auto returns 403 on image endpoints. Find available models in the model marketplace, or call List models
prompt string Yes The prompt. May be omitted for layer decomposition on Seedream pro
size string No Output size, written as width × height (such as 2048x2048) or as a tier name (such as 2K). Accepted forms and ranges differ by model; see the model sections
n integer No Number of images. Forwarded unchanged to GPT-Image, up to 10. Seedream currently cannot use it to generate several images at once: n is forwarded to the upstream, but only 1 image comes back, with no error and no entry in X-Gateway-Unsupported-Parameters; send several requests if you need several images. Dropped for Gemini
quality string See description Generation quality, used by the GPT-Image family; values differ by model, and it is required for gpt-image-2; dropped for Gemini
response_format string No url or b64_json; takes effect only on Seedream (default url). GPT-Image and Gemini always return b64_json, and the gateway drops this parameter
image string | array No Reference images for image-to-image. Seedream accepts a public URL or data:image/<format>;base64,<data>; Gemini accepts them too, written as described in Edit images
user string No End-user identifier. Forwarded unchanged to Seedream and GPT-Image; dropped for Gemini

Other parameters not in the table are forwarded unchanged to Seedream and GPT-Image, and whether they take effect depends on the model; Gemini drops all of them.

How each model is handled

The gateway decides per model how to handle the request body, which determines which parameters take effect:

Model family Model IDs Handling Parameters dropped by the gateway Returned image
Seedream 5.0 bytedance/doubao-seedream-5.0-pro
bytedance/doubao-seedream-5.0-lite
Pass-through None url (default) or b64_json
GPT-Image openai/gpt-image-2
openai/gpt-image-2.5-flare
openai/gpt-image-2.5-sunburst
Pass-through response_format; the two 2.5 models also drop stream and stream_options b64_json
Gemini Image google/gemini-3-pro-image
google/gemini-3.1-flash-image
Contract translation Every parameter except model, prompt, size and image; size is also dropped when it cannot be matched b64_json
  • Pass-through: the body is forwarded unchanged with only the model name rewritten, so other parameters the provider supports can be sent as well. If the upstream does not accept a parameter, you get the upstream's own error.
  • Contract translation: the gateway translates the parameters into the provider's format and drops those it cannot translate.
  • Dropped parameters are listed in the X-Gateway-Unsupported-Parameters response header and the request still runs; with X-Gateway-Strict-Parameters: true it returns 400 instead. Parameters passed through to the upstream are not affected by this header.

For a comparison of model capabilities and use cases, see Multimodal capabilities. The model marketplace is authoritative for which models exist; the sections below list each family's parameters and limits.

Seedream 5.0 (pro / lite)

Seedream models on Volcengine Ark. Pass-through; returns an image URL by default; one generation takes about 20 s.

Parameter Type Description
size string Defaults to 2K. Tier names are recommended, with the aspect ratio described in words in the prompt: 1K, 1.5K and 2K on pro; 2K, 3K and 4K on lite. You can also write widthxheight: pro requires total pixels within [921600, 4624220], lite requires at least 3686400 (the smallest square is 1920x1920, so the common 1024x1024 is rejected), and the aspect ratio must be within [1/16, 16] on both. Do not mix the two forms
response_format string url (default) or b64_json
image string | array Reference images: a public URL or data:image/<format>;base64,<data> (<format> must be lowercase), no more than 10 recommended; see the limits below
output_format string png or jpeg. With layer decomposition it controls only the base image; layers are always PNG
background string opaque (default) or transparent. Image-to-image only, with exactly 1 input image that has an alpha channel
watermark boolean true adds an "AI生成" (AI-generated) watermark in the bottom-right corner. The watermark is added by default when the parameter is omitted; send false if you do not want it
layer_decomposition boolean Pro only, default false. true splits 1 input image into 1 base image and up to 16 PNG layers with alpha channels; image becomes required and must be exactly 1 image, and size accepts tier names only (default auto)
optimize_prompt_options.mode string Pro only. standard (default) or fast (faster, slightly lower quality)

Reference image limits:

Limit Image generation Layer decomposition
Format jpeg, png, webp, bmp, tiff, gif, heic, heif png, jpeg
Total pixels (width × height) [196, 36000000] [262144, 36000000]
Width and height At least 14 px —
Aspect ratio (width/height) [1/16, 16] [1/16, 16]
Size per image ≤ 30 MB ≤ 30 MB
Number of images No more than 10 recommended; the provider currently does not reject more, but the output may be abnormal Exactly 1
  • Pro supports interactive editing: mark the position to change in the prompt with <point>x y</point> or <bbox>x1 y1 x2 y2</bbox> (coordinates normalized to 0–999).
  • A layer decomposition response returns the base image and the layers together in data[], with fields such as z_index, bounding_box, name and description; each request reserves 17 images of rate-limit quota and returns the unused part when it completes. For the pixel sizes of each tier, coordinate conversion and reassembly, see Multimodal capabilities.
  • Other Volcengine Ark parameters can be written directly in the body. With the OpenAI Python SDK, put them in extra_body, for example extra_body={"watermark": False}.

Billing: per image. Pro is tiered by resolution: 1K and 1.5K (≤ 2.61 megapixels) are one tier and 2K is another; layer decomposition has two more tiers (also split into 1K/1.5K and 2K) and is billed by the number of images actually produced (base image + each layer); pro reference images are billed as a separate item, with the first reference image in each request free and each additional one billed per image (this counts input reference images, not output images). Lite has a single tier. 1.5K costs the same as 1K and looks better, so prefer 1.5K unless you have a reason not to.

curl https://api.lyrouter.com/v1/images/generations \
  -H "Authorization: Bearer $LYROUTER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "bytedance/doubao-seedream-5.0-lite",
    "prompt": "A shiba inu in sunglasses on a surfboard, sunset sea, cinematic, wide landscape composition",
    "size": "2K",
    "watermark": false
  }'

GPT-Image (2 / 2.5-flare / 2.5-sunburst)

Pass-through. Parameters match the OpenAI image API, and the result is always b64_json.

Parameter Type Description
quality string Values differ by model; see the table below. Pass it explicitly for every GPT-Image model
size string widthxheight only; tier names are not accepted (4K returns Invalid size '4K'. Expected WIDTHxHEIGHT, for example '1824x1024'.). Must meet the four hard constraints below, or the request returns 400
n integer Number of images, up to 10
background string transparent, opaque or auto
output_format string Output format. gpt-image-2 accepts only png and jpeg, and webp returns 400 Invalid value: 'webp'. Supported values are: 'png' and 'jpeg'.; the 2.5 family accepts png, jpeg and webp
moderation string auto or low
user string End-user identifier
response_format — Dropped by the gateway and listed in the response header: this family always returns b64_json, and the upstream sometimes accepts the parameter and sometimes rejects it
stream, stream_options — Dropped by the gateway for the 2.5 family (an upstream stream makes the request fail); do not send stream to gpt-image-2 either

quality values:

Model Values Default
gpt-image-2 low, medium, high, auto None; required: omitting it returns 400 intermittently (INVALID_REQUEST_BODY); auto behaves as low in measurements
gpt-image-2.5-flare, gpt-image-2.5-sunburst low, medium, high, xhigh, max, auto low (auto behaves like low in measurements)

Whether xhigh and max are available depends on the upstream account, so they may be rejected; if you get Invalid value: 'xhigh', use high instead.

The four hard constraints on size, checked by the provider; violating any one returns 400:

Constraint Provider error text Examples
Width and height both divisible by 16 Invalid size '<width>x<height>'. Width and height must both be divisible by 16. 1008x1008 works; 1254x1254 and 1312x1199 are rejected
Longest edge no more than 3840 Invalid size '<width>x<height>'. The longest edge must be less than or equal to 3840. 3840x2160 works; 4096x4096 and 1024x4096 are rejected
At least about 1 M pixels in total Invalid size '<width>x<height>'. Requested resolution is below the current minimum pixel budget. 1008x1008 (about 1.02 M) works; 512x1024 (about 0.52 M) is rejected
At most about 8.3 M pixels in total Invalid size '<width>x<height>'. Requested resolution exceeds the current pixel budget. 3840x2160 (about 8.29 M) works; 3840x2176 (about 8.36 M) is rejected
  • Latency: one generation took about 20–60 s in measurements, occasionally longer (about 83 s at most); an upstream 400 caused by a bad parameter came back within 2 s. Set the client timeout in minutes, at least 300 s.

Billing: per token, with input text, input image and output priced separately; the upstream reports text and image tokens separately in usage.input_tokens_details, so a prompt of the same length costs a different amount with and without an image. Cache hits have their own price; usage from the 2.5 family has no cache fields, so that item does not occur for it.

Output tokens depend mainly on quality: at 1024x1024, the 2.5 family produces 196 output tokens at low and 7024 at max, so the top level is about 36 times the bottom one. A level with the same name is not the same amount on the two generations: high on the 2.5 family produces as many output tokens as medium on gpt-image-2, so compare models by tokens, not by level name. Also, for GPT-Image more pixels do not mean a higher cost (this applies to GPT-Image only): output tokens do not grow with pixel count; for example, 1024x1536 (about 1.57 million pixels) produces fewer output tokens than 1024x1024 (about 1.05 million pixels).

Gemini Image (3 Pro / 3.1 Flash)

Contract translation: the gateway translates the request into Gemini's native generateContent format, uses only the parameters marked as applied below, and drops the rest, listing them in the response header. The result is always b64_json and cannot be a URL. One generation took 20–250 s in measurements (gemini-3-pro-image), and occasionally had not returned after 300 s.

Parameter Applied Description
prompt Applied Required; omitting it or sending it empty returns 400 prompt is required for this model
size Applied See the table below
image Applied Reference images, written as described in Edit images
n Dropped Send several requests if you need several images
quality Dropped Gemini has no equivalent parameter
response_format Dropped Only b64_json can be returned
user and other parameters Dropped —

How you write size determines the aspect ratio and the resolution:

Form What the gateway does Effect
Tier name: 1K, 2K, 4K Passes it as the resolution tier Controls resolution; the aspect ratio is the upstream default
widthxheight, such as 1376x768 Matches the closest supported ratio (within 2%), then picks the resolution tier by rounding the long edge up Controls both ratio and resolution
Ratio more than 2% off, such as 1000x700 Sends none of size (neither ratio nor tier), and counts size as dropped Returns 200, produces an image and is billed as usual, but with the upstream's default ratio and resolution; the only signal is the response header X-Gateway-Unsupported-Parameters: size. Returns 400 in strict mode
Ratio string, such as 16:9 Passes it unchanged as a tier name The upstream does not recognize it and the request returns 400 (upstream_rejected). For 16:9, write a size with that ratio, such as 1376x768

The provider rejects the 512 tier in production, on both models; do not use it.

Supported aspect ratios: 1:1, 2:3, 3:2, 3:4, 4:3, 4:5, 5:4, 9:16, 16:9, 21:9, 1:4, 4:1, 1:8, 8:1. When you write a width and height, the tier is picked by rounding the long edge up, capped at 4K; a long edge of 704 or less is mapped to 512 by the gateway and may be rejected as well, so keep the long edge above 704. The same tier produces different output tokens on the two models:

Long edge Tier gemini-3-pro-image output tokens gemini-3.1-flash-image output tokens
≤ 1376 1K 1120 1120
≤ 2816 2K 1120 (the 2K tier has no effect; same as 1K) 1680
Larger (capped) 4K 2000 2520

The output size is chosen by the provider from the ratio and resolution tiers and does not equal the requested width and height; for example, gemini-3-pro-image returns a 5504x3072 image for a 4096x2304 request. Rely on the actual width and height of the returned image.

For example, 1024x1024 maps to 1:1 + 1K, and 2048x2048 maps to 1:1 + 2K. For 16:9 at 4K, write 4096x2304; do not copy 5632x3072: its ratio is 1.833, more than 2% off 16:9, so the whole size is dropped. In production, send X-Gateway-Strict-Parameters: true so that such a request returns 400 instead.

Billing: per token, with input, output and thinking priced separately; reference images count toward "input". Thinking tokens appear only when the upstream returns them (gemini-3-pro-image), in usage.output_tokens_details.reasoning_tokens, and usage.total_tokens includes them. Thinking tokens vary from call to call and are decided by the model: production measurements range from 115 to 316, with a median of about 220, about 1.5% of a call's cost. Budget about 220 per call.

{
  "data": [{ "b64_json": "iVBORw0KGgoAAAANSUhEUgAA…" }],
  "usage": {
    "input_tokens": 7,
    "output_tokens": 1120,
    "total_tokens": 1339,
    "output_tokens_details": { "reasoning_tokens": 212 }
  }
}

Request examples

The examples below use openai/gpt-image-2 and save the returned Base64 image to a file. With Seedream, the image comes back as a URL by default: read data[0].url and download it promptly.

curl https://api.lyrouter.com/v1/images/generations \
  --max-time 300 \
  -H "Authorization: Bearer $LYROUTER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "openai/gpt-image-2",
    "prompt": "A shiba inu in sunglasses on a surfboard, sunset sea, cinematic",
    "size": "1024x1024",
    "quality": "medium"
  }'

Response

A successful request returns an object in the OpenAI Images format, with the images in the top-level data array; an error returns an error object. The two 200 examples below are Seedream (returning a URL) and GPT-Image (returning Base64); the 400 is Gemini receiving parameters it does not support with strict mode on; the 403 means the model is not enabled, or a virtual model or Auto was used.

{
  "model": "doubao-seedream-5-0-260128",
  "created": 1789454321,
  "data": [
    {
      "url": "https://ark-acg-cn-beijing.tos-cn-beijing.volces.com/…",
      "size": "1920x1920"
    }
  ],
  "usage": {
    "generated_images": 1,
    "output_tokens": 14400,
    "total_tokens": 14400
  }
}
Field Description
created Unix timestamp (seconds). Not returned by Gemini
model The provider-side model name (returned by Seedream), such as doubao-seedream-5-0-260128; it differs from the model ID in the request
data Array of results; it is an array even for a single image
data[].url Image download URL, returned by Seedream by default. It is a temporary URL signed by the provider and expires after about 24 hours; download and store the image promptly
data[].b64_json The image encoded in Base64. Always returned by GPT-Image and Gemini; returned by Seedream when response_format is b64_json
data[].size The size actually generated (returned by Seedream)
data[].output_format The image format (returned by Seedream pro)
size, quality, output_format, background The generation settings actually used (returned by GPT-Image)
usage Metering information; the fields vary by model, see the table below

Fields in usage

Model family Fields in usage Metered by
Seedream generated_images (number of images), output_tokens, total_tokens; pro also returns input_images (number of input reference images) when reference images are sent Image
GPT-Image input_tokens, input_tokens_details.text_tokens / image_tokens, output_tokens, total_tokens Token
Gemini input_tokens, output_tokens, total_tokens, plus output_tokens_details.reasoning_tokens when there are thinking tokens Token

Do not assume a field is always present; check before reading it. For how each model is billed, see the model sections above; prices are those shown in the model marketplace in the console, and the actual charge for each call is in the request logs.

Response headers

Header Description
X-Gateway-Unsupported-Parameters Present when the gateway dropped parameters; the value is a comma-separated list of parameter names, such as n,quality. The request still ran, and the listed parameters did not take effect

When quotas are configured, the response also carries the x-aigw-quota-* headers; see Gateway headers and extensions.

To read the dropped parameters (the Python and Node.js examples reuse client from the examples above):

curl -sS -D - -o result.json https://api.lyrouter.com/v1/images/generations \
  --max-time 300 \
  -H "Authorization: Bearer $LYROUTER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"google/gemini-3.1-flash-image","prompt":"A single green leaf, flat design","size":"1376x768","n":2}'
# The response headers include: X-Gateway-Unsupported-Parameters: n

Gateway behavior

Compared with calling the upstream directly, calling through LYRouter differs in these ways:

  • Only the requested model is used: image endpoints never switch to another model. When the same model has several channels, the gateway tries the other channels in turn after a failure; virtual models, Auto smart routing and fallback to the workspace's Default Model do not apply to image endpoints. See Retries and fallback.

  • Dropped parameters and strict mode: the gateway drops only the parameters listed in "How each model is handled" above and lists them in the X-Gateway-Unsupported-Parameters response header. In production, check this header, or send X-Gateway-Strict-Parameters: true so that a request containing a parameter that would be dropped returns 400 immediately, without calling the upstream and without charge. With the SDKs, pass it as extra_headers={"X-Gateway-Strict-Parameters": "true"} (Python) or the request option { headers: { "X-Gateway-Strict-Parameters": "true" } } (Node.js). Parameters passed through to the upstream are not affected by this header; the upstream decides whether to accept them.

  • Errors declared in a successful upstream response: when Gemini's upstream rejects a request, it may return HTTP 200 with no image. The gateway rewrites this into an error response, taking the status code from the error the upstream declared: when the upstream rejected the request, error.code is upstream_rejected and error.message is the upstream's original text; when no image was produced, the code is upstream_no_artifact with upstream_finish_reason (such as NO_IMAGE or SAFETY). upstream_status keeps the upstream's original 200. These errors are not retried on another channel; change the prompt or parameters as indicated:

    {
      "error": {
        "message": "upstream produced no image (finishReason: NO_IMAGE)",
        "type": "invalid_request_error",
        "code": "upstream_no_artifact",
        "upstream_status": 200,
        "upstream_finish_reason": "NO_IMAGE",
        "generated_by": "ai-gateway"
      }
    }
    
  • Upstream errors are returned unchanged: parameter errors for pass-through models come from the upstream, with the upstream's format and error codes; Seedream, for example, returns {"error":{"code":"InvalidParameter","message":"..."}}. When the upstream returns an error status with no body, the gateway fills in an error body with upstream_status and generated_by: "ai-gateway", plus upstream_request_id when the upstream supplied a request ID; give that ID to the provider when reporting an issue.

  • Images are not stored in logs: Base64 images in requests and responses are replaced in the logs with a [base64 <bytes>B #<CRC32>] summary. Not seeing the image in the log details does not mean the request failed; the image is in the response body. For models that return a URL, the URL is kept in the logs.

  • Timeouts: image endpoints are synchronous. Seedream takes about 20 s, the GPT-Image family about 20–60 s in measurements, and Gemini 20–250 s in measurements, occasionally more than 300 s. Set the client timeout in minutes, at least 300 s, rather than the 30 s you use for text; after a client timeout, do not resubmit right away; first check the result of the previous request in the request logs.

Common errors

Errors returned by the gateway take the form {"error":{"message":"...","type":"...","code":"..."}}; parameter errors for pass-through models come from the upstream in the upstream's format.

Status code error.message error.code Cause and fix
400 you must provide a model parameter missing_model No model was given and the workspace has no Default Model. Always specify the model ID on image endpoints
400 unsupported parameters for this model: <names> unsupported_parameters X-Gateway-Strict-Parameters: true was sent and the request contains parameters that would be dropped. Remove the listed parameters, or use a model that supports them
400 prompt is required for this model invalid_parameter No prompt, or an empty one, was sent to Gemini
400 The upstream's text, such as Request contains an invalid argument. upstream_rejected Gemini's upstream rejected the request, for example because size was written as 16:9. Fix the parameters as the text says
400 upstream produced no image (finishReason: <reason>) upstream_no_artifact Gemini produced no image. Change the prompt or content according to upstream_finish_reason and retry
400 The parameter `size` specified in the request is not valid: image size must be at least 3686400 pixels InvalidParameter The size is below Seedream lite's minimum. Use the 2K tier or a larger size, such as 1920x1920
400 Invalid size '<width>x<height>'. Width and height must both be divisible by 16. — The GPT-Image width or height is not a multiple of 16; returned by the upstream
400 Invalid size '<width>x<height>'. The longest edge must be less than or equal to 3840., Invalid size '<width>x<height>'. Requested resolution is below the current minimum pixel budget., Invalid size '<width>x<height>'. Requested resolution exceeds the current pixel budget. — The GPT-Image size has a longest edge above 3840, or its total pixel count is not between about 1 M and about 8.3 M; returned by the upstream. Adjust it against the four hard constraints on size above
400 Invalid size '4K'. Expected WIDTHxHEIGHT, for example '1824x1024'. — A tier name was sent to GPT-Image. Write it as widthxheight
400 Invalid value: 'xhigh' — The upstream account does not support the xhigh / max levels of quality (availability depends on the upstream account). Use high
400 The upstream's text INVALID_REQUEST_BODY The GPT-Image request body is invalid; first check that quality is set: omitting it on gpt-image-2 returns 400 intermittently
400 This model does not support the images API unsupported_model_api The interfaces the model declares (api_types in List models) do not include the image endpoints, for example a chat model used on this endpoint. A chat model that declares no api_types does not trigger this error: the request is forwarded upstream and may return 404 upstream_not_found, or a 200 with no image (such as {"data":{"content":null}}). Use only image models on image endpoints
403 Model is not available in the model plaza model_not_available The workspace has not enabled this model, or @vmodel/<name> or lyrouter/auto was used. Ask an administrator to enable it in the model marketplace, or use a concrete model ID that is enabled