GPT Image 2.5 output_compression returns 400 on Sume: use Pillow
OpenAI offers output_compression 0-100 for JPEG and WebP; Sume returns 400 unsupported_parameter for it. Request png, jpeg or webp, then compress with Pillow.

Sume does not serve output_compression: a request that sends it returns 400 unsupported_parameter. OpenAI's guide documents a 0 to 100 compression setting for JPEG and WebP output, but on Sume you ask for output_format of png, jpeg or webp and shrink the file yourself afterwards, for example with Pillow.
What each side does
Both rows are from the pages I read.
| Item | OpenAI guide | Sume Image API |
|---|---|---|
| output_format | PNG, JPEG, WebP | png, jpeg, webp (svg is in the schema, no model lists it) |
| output_compression | 0-100 for JPEG and WebP | In the schema, not served; 400 unsupported_parameter |
| Transparent background | background transparent with PNG or WebP | background on ChatGPT Image 2.5, both variants |
Why a 400 and not a silent drop
The Sume docs call output_compression and seed schema-only: no model advertises them, so the catalog rejects them instead of dropping them. That is deliberate. It means a silent quality change never reaches you, but it also means a client ported from OpenAI's samples fails until you remove the field.
A Pillow recipe
This script requests a PNG, downloads the Sume-hosted URL and saves a JPEG at quality 82. It needs pip install pillow requests and a SUME_API_KEY. The quality value 82 is an arbitrary starting point, not a Sume or OpenAI recommendation; compare file sizes at your own settings. The script stops with a message if Sume returns a 202 job.
import io, os, requests
from PIL import Image
H = {"Authorization": "Bearer " + os.environ["SUME_API_KEY"]}
r = requests.post("https://api.sume.com/v1/images", headers=H, timeout=60, json={
"model": "openai/gpt-image-2.5",
"prompt": "a product photo of a red kettle on a white table",
"output_format": "png",
})
r.raise_for_status()
if r.status_code == 202:
raise SystemExit("slow job (202): read it from GET /v1/jobs/{id}/result")
url = r.json()["data"][0]["url"]
img = Image.open(io.BytesIO(requests.get(url, timeout=60).content)).convert("RGB")
img.save("out.jpg", "JPEG", quality=82, optimize=True)
print("saved out.jpg", os.path.getsize("out.jpg"), "bytes")One caution
If you need transparency, keep PNG or WebP. JPEG has no alpha channel, so the convert("RGB") step above would flatten it.
Sources
Related posts
More in Developers
- Graph API rate-limit codes 4, 17, 32, 613: stop, reuse the Sume job
Meta documents error codes 4, 17, 32 and 613 for rate limits. Map each to a pause and publish the stored Sume result later instead of re-rendering.
- Graph API X-App-Usage call_count: pause a Reel publisher early
Meta's X-App-Usage header reports call_count, total_cputime and total_time as percentages. Read it after each call and pause your publisher before the limit.
- Griffin 10 ms audio packets vs Sume TTS: async jobs, no streaming
Tavus Griffin emits speech in packets as small as 10 ms. Sume's TTS Router lists streaming TTS as a non-goal, so audio arrives as a finished file for lip sync.
- Grok Imagine Image 2.0 makes 10 images per request; Sume's n cap
xAI says grok-imagine-image-2.0 returns up to 10 images per request at $0.04 each. Sume's n is 1-10 per request, with a lower per-model cap on x-ai/grok-image.
Written by Sume