Create image edit
Last updated September 1, 2026
Edit an image with references. OpenAI Images edits shape, so the official SDKs work unchanged.
Edit an image with one or more references. The body is multipart/form-data: reference images are uploaded as files, and the remaining parameters are ordinary form fields.
https://gateway.amux.ai/v1/images/editsAuthorization
headerAuthorizationstringRequiredBearer <your Amux AI key> An Amux key created in the console. If you lose it, you can view it again on the keys page.
Request
multipart/form-datamodelstringRequiredA catalog model ID.
promptstringRequiredWhat to change.
imagearray<string>RequiredReference images. At most 16, 25MB each.
Both image and image[] are accepted. OpenAI SDKs typically send
the first for a single image and the second for several.
maskstringA mask; transparent areas mark what to change. Three hard rules:
1. It must be a PNG with an alpha channel (add one if starting
from grayscale);
2. Same dimensions as the image, and under 4MB — the mask has its
own, much tighter limit than a reference image (we cap those at 25MB);
3. With several reference images it applies only to the first.
This field is only meaningful alongside a reference image. On its
own, it is ignored and noted in amux.notes.
nintegerHow many images. Maximum 10; must be 1 when streaming.
sizestring1024x1024 / 1536x1024 / 1024x1536 / 2048x2048 / 2048x1152 / 3840x2160 / 2160x3840 / auto (default), or any legal pixel string — same constraints as the generation endpoint.
aspect_ratiostringAn alternative spelling of size (the Google-ecosystem form), used together with image_size. Send one form or the other; if both are given, size wins. The accepted set differs per model — see the model pages.
⚠️ On the OpenAI models, prefer size. Those upstreams take exact pixel sizes only, so a ratio is folded into one of them; the fold is lossy, and a ratio with no exact match is approximated or dropped, with a note in amux.notes. The xAI image models are the other way round: they take aspect_ratio natively and do not accept size at all.
image_sizestringResolution tier, used with aspect_ratio. The accepted set differs per model.
qualitystringQuality tier.
backgroundstringtransparent / opaque / auto. Transparency needs png or webp.
output_formatstringpng, jpeg or webp.
output_compressionstringCompression level; jpeg / webp only, defaults to 100.
input_fidelity"high" | "low"Fidelity to the original, default low. Controls how closely
everything you did not ask to change stays put — drifting faces,
logos and text usually trace back to it.
⚠️ Differs per model: gpt-image-1.5 supports it;
**gpt-image-2, gpt-image-2.5-flare and gpt-image-2.5-sunburst
do not** — gpt-image-2 always works at high fidelity, and on
GPT-Image-2.5 the field is rejected upstream. On those three the
gateway drops it before the request is sent and records the fact in
amux.notes, so a call migrated from gpt-image-1.5 still
succeeds.
Edits only; sent to the generation endpoint it is dropped, with a
note in amux.notes.
userstringEnd-user identifier for abuse monitoring.
streamstringReturn SSE; the events are image_edit.partial_image / image_edit.completed. Requires n of 1 and at least one provider that streams. Note that multipart fields are strings, so write stream=true.
partial_imagesstringHow many low-resolution previews while streaming (0-3, default 0).
Response
200responseEdited. Same shape as the generation endpoint.
400responseMalformed, or using something this path does not support (URL-form references). Also covers "streaming asked for but no provider streams" and "streaming with n above 1".
402responseThe available balance cannot cover the reserve.
503responseToo many tasks in flight. Retry later.
Supported models
Six: gpt-image-2.5-flare, gpt-image-2.5-sunburst, gpt-image-2, gpt-image-1.5,
x-ai/grok-imagine-image-2.0 and x-ai/grok-imagine-image-quality.
Beyond the differences on the generation endpoint, edits add three more — the "Reference images" and "Mask" sections below describe the gpt-image rules and do not apply to the two xAI models:
| gpt-image-2.5 (flare / sunburst) | gpt-image-2 | gpt-image-1.5 | grok-imagine-image-2.0 | grok-imagine-image-quality | |
|---|---|---|---|---|---|
input_fidelity | not accepted | not accepted (always high fidelity) | high / low, default low | not accepted | not accepted |
mask | supported | supported | supported | unsupported | unsupported |
| Reference images | up to 16 | up to 16 | up to 16 | up to 5 | up to 3 |
⚠️ input_fidelity is rejected upstream on GPT-Image-2.5, not ignored. We drop the
field before the request leaves the gateway and record it in amux.notes, so a call
migrated from gpt-image-1.5 keeps working; sending it straight to the vendor would
return a 400.
Own references: gpt-image-2.5-flare · gpt-image-2.5-sunburst · gpt-image-2 · gpt-image-1.5 · grok-imagine-image-2.0 · grok-imagine-image-quality.
The body is multipart
Reference images as files, everything else as ordinary fields. ⚠️ Form fields are
always strings, so streaming is stream=true as text, not a boolean.
The field name may be image or image[] — official SDKs send the former for one image
and the latter for several. Up to 16 images, 25MB each.
A mask has three hard requirements
- It must be a PNG with an alpha channel — the transparent areas get edited;
- Same dimensions as the image, and under 4MB;
- With several reference images, the mask applies only to the first one.
A mask only takes effect alongside a reference image. On its own it is dropped, with an
explanation in amux.notes — otherwise the upstream just answers "image is required",
which does not point at the mask.
One more cost than generation
Reference images count as input tokens. The reserve assumes an upper bound per image and settles against the actual usage in the response.
Editing works asynchronously too
Send the same fields to /v1/tasks (also multipart).
Errors
The error shape matches OpenAI. See Errors and retries for the
type values and their retry semantics.
curl https://gateway.amux.ai/v1/images/edits \
-H "Authorization: Bearer $AMUX_API_KEY" \
-F "model=<string>" \
-F "prompt=<string>" \
-F "image=@/path/to/image.png" \
-F "mask=@/path/to/mask.png" \
-F "n=0" \
-F "size=<string>" \
-F "aspect_ratio=<string>" \
-F "image_size=<string>" \
-F "quality=<string>" \
-F "background=<string>" \
-F "output_format=<string>" \
-F "output_compression=<string>" \
-F "input_fidelity=high" \
-F "user=<string>" \
-F "stream=<string>" \
-F "partial_images=<string>"{
"created": 1786000000,
"data": [
{
"b64_json": "<string>",
"revised_prompt": "<string>"
}
],
"usage": {
"input_tokens": 0,
"output_tokens": 0,
"total_tokens": 0
},
"amux": {
"task_id": "<string>",
"generation_id": "<string>",
"provider": "<string>",
"cost_nano": "<string>",
"images": [
{
"index": 0,
"url": "<string>"
}
],
"notes": [
"<string>"
]
}
}