GPT Image 2.5 custom size: the pixel rules and the 1024x1536 call
GPT Image 2.5 on Sume takes custom pixels via image_size: multiples of 16, edge up to 3840, aspect up to 3:1. Check your size, then call it with Python.

Yes, 1024x1536 works: both edges are multiples of 16, the longest edge is under 3840, the ratio is 3:2, and 1,572,864 pixels sits inside the allowed range. Send it as image_size: {"width": 1024, "height": 1536} on openai/gpt-image-2.5. Do not put it on size, which rejects WxH values.
OpenAI's own guide (read 2026-10-06) lists custom-size rules too. Sume's docs state the same shape of constraints for the GPT rows, and Sume validates before it submits.
The rules, as Sume states them
| Rule | Limit | 1024x1536 |
|---|---|---|
| Each edge | Multiple of 16 | Yes (64 x 16 and 96 x 16) |
| Longest edge | 3840 at most | 1536 |
| Aspect ratio | 3:1 at most | 1.5:1 |
| Total pixels | 655,360 to 8,294,400 | 1,572,864 |
Call it and check the file
The script asks for an opaque background and opens the result with Pillow to confirm the size that came back.
import io, os, requests
from PIL import Image
key = os.environ.get("SUME_API_KEY")
if not key:
raise SystemExit("set SUME_API_KEY")
r = requests.post(
"https://api.sume.com/v1/images",
headers={"Authorization": f"Bearer {key}"},
json={"model": "openai/gpt-image-2.5", "quality": "medium",
"image_size": {"width": 1024, "height": 1536},
"background": "opaque",
"prompt": "Tall product poster, matte bottle on a pale shelf"},
timeout=90,
)
print(r.status_code)
if r.status_code == 200:
img = requests.get(r.json()["data"][0]["url"], timeout=60)
im = Image.open(io.BytesIO(img.content))
print(im.size, im.mode)If it fails
- A
400names the field that broke a rule. A 1000x1500 request fails because 1000 is not a multiple of 16. - A
202means it took longer than 30 seconds. Poll thestatus_urland fetch the result. - Larger sizes cost more and are more likely to take the
202path.
Quality is a separate choice
Size and quality are different dials. If you omit quality on this row, the default is high, and auto reserves max. The cost guard post in this series covers that, so set quality on purpose when you set size.
Choosing a size on purpose
Pick the size from where the image will live, not from the largest number allowed. A tall poster, a wide banner and a square tile are three different requests, and each should use the smallest size that still looks sharp where it is shown.
The 3:1 limit matters for banners. A 3000x1000 request is exactly 3:1, but neither edge is a multiple of 16, so it fails; 3008x1008 passes, with a ratio just under 3:1. Round each edge to the nearest multiple of 16 before you send it, and let your code do that so a typo never reaches the API.
Sources
Related posts
More in Developers
- 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.
- GPT Image 2.5 on Sume: no quality means high, auto reserves max
Skipping quality on GPT Image 2.5 means high ($0.0355 at 1280x720). Sending auto reserves max ($0.1420). What that does to a budget.
- Sume MCP consent: granting write always includes read
Sume's MCP consent offers mcp:read (required) and mcp:write (opt-in). A write grant always includes read, and there is no paid scope.
- Haystack MCPTool 30-second timeout vs Sume jobs_wait holds
Haystack's MCPTool times out tool calls at 30 seconds; Sume's jobs_wait holds 50 to 55. Raise invocation_timeout or wait in shorter slices.
Written by Sume