GPT Image 2.5 mask_url on Sume: build the PNG mask with Pillow
mask_url works only on the GPT Image 2.5 rows and must be a public HTTPS link. OpenAI wants an alpha channel and a matching size. A Pillow script builds one.

On Sume, mask_url is accepted only by the GPT Image 2.5 rows, openai/gpt-image-2.5 and openai/gpt-image-2.5-sunburst, and it has to be a public HTTPS URL. Other image rows return a 400 for it. The mask file itself follows OpenAI's rules: its guide (read 2026-10-06) says the mask needs an alpha channel, the same format and size as the image, and a size under 50MB.
So the work is in building the file correctly and hosting it where Sume can fetch it.
Build the mask
This script makes an opaque black PNG the same size as your source and cuts a transparent rectangle where the edit should happen. Which area the model edits is defined in OpenAI's guide, so read that page and confirm on a low-quality test call before you trust the direction.
import sys
from PIL import Image, ImageDraw
def make_mask(src: str, dst: str, box: tuple) -> None:
size = Image.open(src).size
mask = Image.new("RGBA", size, (0, 0, 0, 255))
ImageDraw.Draw(mask).rectangle(box, fill=(0, 0, 0, 0))
mask.save(dst, format="PNG")
print("mask", size, "alpha at box start:", mask.getpixel(box[:2])[3])
if __name__ == "__main__":
if len(sys.argv) != 7:
raise SystemExit("usage: mask.py SRC DST X0 Y0 X1 Y1")
x0, y0, x1, y1 = map(int, sys.argv[3:])
make_mask(sys.argv[1], sys.argv[2], (x0, y0, x1, y1))Three masks, three conventions
| Where | Mask rule | How you pass it |
|---|---|---|
| Sume GPT Image 2.5 rows | Public HTTPS URL only | mask_url field |
| OpenAI image guide | Alpha channel, same format and size, under 50MB | Its own API fields |
| Ideogram precise edit | Black marks the area to edit, white the area to keep; same size as the image; needs both colors | mask upload |
| Sume Ideogram 4.5 row | No mask field | Edit by prompt and reference only |
Send it
- Upload the source and the mask to storage that serves public HTTPS, with no login and no localhost.
- Send the source as the first
input_referencesentry and the mask asmask_url. - Use
quality: "low"while you check the direction and the edge. - If the call fails with a message about an unfetchable image, the usual cause is a link that is not public.
Do not reuse an Ideogram mask
Ideogram's convention is the opposite style: a black and white image, not an alpha cutout. A mask that works for one will not work for the other, so keep them in separate folders and name them by target model.
Sources
Related posts
More in Developers
- Heroku H12 at 30 seconds: call Sume async, not sync
Heroku's router ends a request at 30 s (H12). Sume sync mode waits up to 30 s too. Submit async, return 202 to the browser, then poll or take a webhook.
- How long can an AI video Format run take? 90-minute limit
A Sume Format run expires 90 minutes after creation, sooner if silent. How to poll with backoff, when to use a webhook, and what expired means.
- How many 30-second videos can a Sume Pro key run at once? Wave math
Pro runs 4 generations at once and queues 20 more, so 24 accepted jobs. Use the plan table and a Python function to plan a 50-clip batch in waves.
- How many images can I get per AI image request? Read n, don't guess
Sume's docs allow n up to 10 per call but say per-model ceilings are lower. Here is how to read each model's real n range from the catalog in one request.
Written by Sume