curl https://api.pipellm.ai/v1/images/edits \
-H "Authorization: Bearer $PIPELLM_API_KEY" \
-F model="gpt-image-2.5-sunburst" \
-F image="@room.png" \
-F mask="@room-mask.png" \
-F prompt="Replace the sofa with a green velvet one" \
-F size="1024x1024"
import base64
import os
from openai import OpenAI
client = OpenAI(
api_key=os.environ["PIPELLM_API_KEY"],
base_url="https://api.pipellm.ai/v1",
)
result = client.images.edit(
model="gpt-image-2.5-sunburst",
image=open("room.png", "rb"),
mask=open("room-mask.png", "rb"),
prompt="Replace the sofa with a green velvet one",
size="1024x1024",
)
with open("room-edited.png", "wb") as f:
f.write(base64.b64decode(result.data[0].b64_json))
import fs from "node:fs";
import OpenAI, { toFile } from "openai";
const client = new OpenAI({
apiKey: process.env.PIPELLM_API_KEY,
baseURL: "https://api.pipellm.ai/v1",
});
const result = await client.images.edit({
model: "gpt-image-2.5-sunburst",
image: await toFile(fs.createReadStream("room.png"), "room.png"),
mask: await toFile(fs.createReadStream("room-mask.png"), "room-mask.png"),
prompt: "Replace the sofa with a green velvet one",
size: "1024x1024",
});
fs.writeFileSync("room-edited.png", Buffer.from(result.data[0].b64_json, "base64"));
{
"created": 1726400000,
"size": "1024x1024",
"quality": "medium",
"output_format": "png",
"background": "opaque",
"data": [
{ "b64_json": "iVBORw0KGgoAAAANSUhEUgAA..." }
],
"usage": {
"input_tokens": 342,
"input_tokens_details": { "text_tokens": 14, "image_tokens": 328 },
"output_tokens": 1056
}
}
Edit an image
Edit an existing image, optionally masked, with GPT image models.
POST
/
v1
/
images
/
edits
curl https://api.pipellm.ai/v1/images/edits \
-H "Authorization: Bearer $PIPELLM_API_KEY" \
-F model="gpt-image-2.5-sunburst" \
-F image="@room.png" \
-F mask="@room-mask.png" \
-F prompt="Replace the sofa with a green velvet one" \
-F size="1024x1024"
import base64
import os
from openai import OpenAI
client = OpenAI(
api_key=os.environ["PIPELLM_API_KEY"],
base_url="https://api.pipellm.ai/v1",
)
result = client.images.edit(
model="gpt-image-2.5-sunburst",
image=open("room.png", "rb"),
mask=open("room-mask.png", "rb"),
prompt="Replace the sofa with a green velvet one",
size="1024x1024",
)
with open("room-edited.png", "wb") as f:
f.write(base64.b64decode(result.data[0].b64_json))
import fs from "node:fs";
import OpenAI, { toFile } from "openai";
const client = new OpenAI({
apiKey: process.env.PIPELLM_API_KEY,
baseURL: "https://api.pipellm.ai/v1",
});
const result = await client.images.edit({
model: "gpt-image-2.5-sunburst",
image: await toFile(fs.createReadStream("room.png"), "room.png"),
mask: await toFile(fs.createReadStream("room-mask.png"), "room-mask.png"),
prompt: "Replace the sofa with a green velvet one",
size: "1024x1024",
});
fs.writeFileSync("room-edited.png", Buffer.from(result.data[0].b64_json, "base64"));
{
"created": 1726400000,
"size": "1024x1024",
"quality": "medium",
"output_format": "png",
"background": "opaque",
"data": [
{ "b64_json": "iVBORw0KGgoAAAANSUhEUgAA..." }
],
"usage": {
"input_tokens": 342,
"input_tokens_details": { "text_tokens": 14, "image_tokens": 328 },
"output_tokens": 1056
}
}
Edits take one or more source images and a prompt describing the change. With a mask, only the transparent region is repainted; without one, the model rewrites the whole frame guided by the references.
Two request encodings work, and PipeLLM passes both through:
The response shape matches Create an image: the bytes come back base64-encoded in
multipart/form-datawith the image bytes uploaded directly. This is what the OpenAI SDK sends.application/jsonwith animagesarray offile_idorimage_urlentries, up to 16 references.
file | array
required
Source image, or several. Send file parts under
image[] in multipart, or the JSON images array. PNG, JPEG, or WebP.string
required
What the edited image should show. Up to 32,000 characters on GPT image models.
string
Image model ID, for example
gpt-image-2.5-sunburst.file
A PNG whose transparent pixels mark the region to repaint. Must match the source dimensions. Omit it to let the model edit the whole image.
integer
default:"1"
Number of images to return, 1–10.
string
default:"auto"
auto, 1024x1024, 1536x1024, 1024x1536, or a custom WIDTHxHEIGHT divisible by 16.string
default:"auto"
low, medium, high, or auto. The gpt-image-2.5 variants add xhigh and max.string
default:"low"
high preserves faces, logos, and fine texture from the source more closely, at a higher input-token cost. low gives the model more freedom.string
default:"auto"
transparent, opaque, or auto. Transparent requires png or webp output.string
default:"png"
png, jpeg, or webp.integer
default:"100"
Compression level 0–100, for
jpeg and webp only.string
Stable end-user identifier.
curl https://api.pipellm.ai/v1/images/edits \
-H "Authorization: Bearer $PIPELLM_API_KEY" \
-F model="gpt-image-2.5-sunburst" \
-F image="@room.png" \
-F mask="@room-mask.png" \
-F prompt="Replace the sofa with a green velvet one" \
-F size="1024x1024"
import base64
import os
from openai import OpenAI
client = OpenAI(
api_key=os.environ["PIPELLM_API_KEY"],
base_url="https://api.pipellm.ai/v1",
)
result = client.images.edit(
model="gpt-image-2.5-sunburst",
image=open("room.png", "rb"),
mask=open("room-mask.png", "rb"),
prompt="Replace the sofa with a green velvet one",
size="1024x1024",
)
with open("room-edited.png", "wb") as f:
f.write(base64.b64decode(result.data[0].b64_json))
import fs from "node:fs";
import OpenAI, { toFile } from "openai";
const client = new OpenAI({
apiKey: process.env.PIPELLM_API_KEY,
baseURL: "https://api.pipellm.ai/v1",
});
const result = await client.images.edit({
model: "gpt-image-2.5-sunburst",
image: await toFile(fs.createReadStream("room.png"), "room.png"),
mask: await toFile(fs.createReadStream("room-mask.png"), "room-mask.png"),
prompt: "Replace the sofa with a green velvet one",
size: "1024x1024",
});
fs.writeFileSync("room-edited.png", Buffer.from(result.data[0].b64_json, "base64"));
{
"created": 1726400000,
"size": "1024x1024",
"quality": "medium",
"output_format": "png",
"background": "opaque",
"data": [
{ "b64_json": "iVBORw0KGgoAAAANSUhEUgAA..." }
],
"usage": {
"input_tokens": 342,
"input_tokens_details": { "text_tokens": 14, "image_tokens": 328 },
"output_tokens": 1056
}
}
data[].b64_json, and usage.input_tokens_details.image_tokens covers the source images you uploaded.
Combining references
With several source images the model composes across them — a product plus a scene, a person plus an outfit. Order matters: describe the references in the prompt in the order you send them, for example “dress the person from the first reference in the outfit from the second”. Masks apply to the first image only.Long requests
Edits use the same keep-alive behavior as generation: after 90 seconds of upstream silence the gateway writes a whitespace padding chunk every 30 seconds ahead of the JSON body. See Long requests.Errors
Same envelope as Errors.400 invalid_request_error
400 invalid_request_error
Mask dimensions not matching the source, an unreadable upload, or a
size the model rejects.{
"error": {
"type": "invalid_request_error",
"code": "400",
"message": "The mask must have the same dimensions as the image"
}
}
401 authentication_error
401 authentication_error
{
"error": {
"type": "authentication_error",
"code": "401",
"message": "Incorrect API key provided. Please visit https://console.pipellm.ai/account/api-keys to find your API key."
}
}
413 invalid_request_error
413 invalid_request_error
The upload exceeded the accepted body size. Downscale the source before sending.
429 rate_limit_error
429 rate_limit_error
See Rate Limits.
Was this page helpful?