Skip to content

Image generation and editing

primerouter exposes two OpenAI-compatible image endpoints:

EndpointUseRequest format
POST /v1/images/generationsText to imageJSON
POST /v1/images/editsImage to image, multiple reference imagesmultipart/form-data

Available image models and prices are on the pricing page, under "Image models". There are currently two families, gpt-image-2 and grok-imagine-image. The request shape is the same, but whether size takes effect and what comes back differ — see each model's section below.

Text to image

bash
curl https://primerouter.ai/v1/images/generations \
  -H "Authorization: Bearer $PRIMEROUTER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-image-2",
    "prompt": "An orange cat on a windowsill in soft morning light",
    "output_format": "png",
    "response_format": "b64_json"
  }'

The image comes back in data[].b64_json as a base64 string.

Passing response_format=url returns a data: inline URL — not a downloadable http link.

Image editing and multiple reference images

Image editing goes through /v1/images/edits and must be sent as a form (multipart/form-data), not JSON.

For multiple reference images, repeat image[] — one per file:

bash
curl https://primerouter.ai/v1/images/edits \
  -H "Authorization: Bearer $PRIMEROUTER_API_KEY" \
  -F model=gpt-image-2 \
  -F "image[]=@layout.png" \
  -F "image[]=@product.png" \
  -F prompt="Place the product from the second image into the layout of the first. Keep all promotional text from the layout." \
  -F output_format=png

The OpenAI SDK works the same way:

python
from openai import OpenAI

client = OpenAI(base_url="https://primerouter.ai/v1", api_key="sk-...")
result = client.images.edit(
    model="gpt-image-2",
    image=[open("layout.png", "rb"), open("product.png", "rb")],
    prompt="Place the product from the second image into the layout of the first. Keep all promotional text from the layout.",
)

Notes:

  • image, image[], and image[0]/image[1] are all accepted, and forwarded in the order you gave them
  • The gateway does not cap the number of reference images; the upstream does. A single request body is limited to 32MB by default
  • mask is optional (field name mask); only the first file is used
  • Other form fields (background, output_format, output_compression, moderation, …) are forwarded as-is. On the JSON /v1/images/generations path, only standard fields are forwarded

Spell out everything you want kept

Image editing redraws from the prompt — it is not a local edit on the original canvas. Elements in a reference image are not guaranteed to survive unless the prompt asks for them.

If you want the title, feature bullets, and badges from the first image kept, say so:

Place the product from the second image into the layout of the first.
Keep all promotional text from the layout.

Without that second sentence, the result often keeps only the main title and drops the rest of the layout. This is not a reference image being ignored — both images reach the model; they just were not asked to be preserved.

gpt-image-2 size and quality limits

Read this first

gpt-image-2 currently cannot control output resolution. This is a limitation of the upstream image endpoint, not a matter of how you write the parameters.

What this means:

  • size does not set the resolution. Whether you send 512x512, 1024x1024, or 3840x2160, the output is roughly 1.57 megapixels
  • size only influences the aspect ratio in text-to-image, and only for a limited set (1:1, 3:2, 2:3, 3:4, 16:9). Anything outside that set — or a requested pixel count below ~0.69MP — falls back to 1:1
  • In image editing size has essentially no effect; the model picks the shape from the prompt and the reference images
  • quality has no effect at all. low / medium / high make no difference; upstream normalizes it to auto
  • Asking for a resolution in the prompt does not work either

Measured output sizes:

Requested sizeActual outputPixels
512×5121254×12541.57MP
1024×10241254×12541.57MP
600×8001254×12541.57MP
3840×21601672×9411.57MP
1536×10241536×10241.57MP

If you need exact pixel dimensions, resize the result yourself.

Grok Imagine (grok-imagine-image)

grok-imagine-image uses the same two endpoints with the same request shape — just change model:

bash
curl https://primerouter.ai/v1/images/generations \
  -H "Authorization: Bearer $PRIMEROUTER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "grok-imagine-image",
    "prompt": "An orange cat on a windowsill in soft morning light",
    "size": "2048x1152"
  }'

The biggest difference from gpt-image-2: size takes effect.

How the size is decided

Grok has only two resolutions, 1K and 2K — there is no 4K. The width and height in size are converted into "resolution + aspect ratio" before reaching the model:

  • Long edge ≤ 1024 → 1K, otherwise → 2K. Grok has no 4K; requesting a 4K size still yields a 2K image
  • The aspect ratio snaps to the nearest of: 1:1, 16:9, 9:16, 4:3, 3:4, 3:2, 2:3, 2:1, 1:2, 19.5:9, 9:19.5, 20:9, 9:20
  • The actual pixel dimensions are fixed per resolution and ratio — they will not exactly match the width and height you sent
  • You can also send size=1k / size=2k directly to set only the resolution and let the model pick the ratio
  • Without size, the image is 2K

Measured:

Requested sizeText-to-image outputImage-edit output
(none)2K, ratio chosen by the model (measured 2496×1664)2K, follows the reference image (measured 2048×2048)
1024×10241024×10241024×1024
2048×11522816×15842816×1584
3840×21602816×15842816×1584

quality has no effect on this model.

Response format

  • Text-to-image: response_format defaults to url, and the URL is a directly downloadable https link (unlike the data: inline URL from gpt-image-2). It is a temporary address — save the image promptly. b64_json also works
  • Image editing: always returns a link; response_format has no effect
  • The image may be JPEG or PNG

Only these parameters are honored

Text-to-image forwards model, prompt, n, size, and response_format; image editing adds image / image[] (up to 3 reference images). output_format, background, moderation and similar fields do nothing for Grok.

Billing

Billed by the tier of the requested size — see the tier table in the Billing section below; without size, 2K. Per-tier prices are on the pricing page.

Billing

Image models are billed by image count × size tier, not by tokens.

The tier is decided by the long edge of the output image:

Long edgeTier
≤ 10241K
1025 – 20482K
> 20484K

Per-tier prices are on the pricing page.

Three things that are easy to get wrong:

  1. The tier comes from the image you actually got, not the size you asked for. Request 4K, receive a 2K image, pay 2K. Grok is the exception: it is billed by the tier of the requested size (see above)
  2. You pay for the images actually returned, not for the n you requested
  3. Group multipliers are not applied. The configured price is the price

gpt-image-2 is always 2K

As covered above, gpt-image-2 always renders about 1.57 megapixels. Its long edge is therefore never smaller than 1254 (the square case), so it can never reach the 1K tier, and practically never reaches 4K.

gpt-image-2 is effectively always billed at 2K. Requesting a small size, or asking for a small image in the prompt, will not lower the price.

Troubleshooting

The admin Logs → Details view shows which tier a request was billed at:

大小 600x800, 请求品质 medium, 生成数量 1, 图片档位 2K(来源:输出尺寸,实际尺寸 1254x1254)
  • 大小 (size) and 请求品质 (requested quality) are what you sent, not what upstream accepted
  • 实际尺寸 (actual size) is decoded from the returned image bytes — billing uses this
  • A source of 默认 (default) means neither the request nor the response yielded a size, and the request was billed at 2K

When a charge looks wrong, start with 图片档位 (tier) and 生成数量 (count).

Built for transparent, auditable, crypto-native AI inference. About · Terms · Privacy