Sume Image API 400 unsupported_parameter: which field fails where
Which Sume image models list quality, resolution, mask_url, background, output_format and references, and which never do (seed, stream). Plus a check script.

The Sume Image API returns 400 unsupported_parameter when a request sets a parameter the selected model does not list, and it never drops the field silently. No model lists seed, output_compression or streaming today, so those always fail. mask_url and background are listed by ChatGPT Image 2.5 (Flare and Sunburst) only. quality, resolution and output_format are listed by a handful of rows each, and the table below says which.
This is from the catalog on origin/main and the Sume docs, read 2026-10-08. The endpoints route is the source of truth, so the pre-flight script below checks it before you send.
Who lists what
Every row lists prompt, aspect_ratio and n. The rest varies.
| Field | Rows that list it |
|---|---|
| seed, output_compression, streaming | None |
| mask_url, background | ChatGPT Image 2.5 (Flare) and ChatGPT Image 2.5 Sunburst only |
| quality | ChatGPT Image 2 (3 values), ChatGPT Image 2.5 and Sunburst (6 values), Ideogram V3 and 4.5 (low, medium, high) |
| resolution | Nano Banana 2.1 and Pro (512 to 4K), Imagen 4 Ultra and Ideogram 4.5 (1K, 2K), Soul (720p, 1080p) |
| output_format | Not listed on Soul or Ideogram 4.5; webp only on Recraft V4; png, jpeg, webp elsewhere |
| input_references above 0 | Not on Soul, Qwen Image Max, Imagen 4 Fast, Imagen 4 Ultra, Recraft V4 |
| n above 1 | Every row except Grok Image |
A pre-flight check
This function reads the endpoint record and returns the keys in your body that the row will reject. It treats an input_references descriptor with a maximum of 0 as unsupported, since the docs say such a model rejects references. It checks names, not values; a value outside an enum is the other thing to compare against the descriptor.
import os, requests
SKIP = {"model", "prompt", "mode", "webhook_url", "provider"}
def unsupported(model_id, body):
url = f"https://api.sume.com/v1/images/models/{model_id}/endpoints"
headers = {"Authorization": f"Bearer {os.environ['SUME_API_KEY']}"}
ep = requests.get(url, headers=headers, timeout=30).json()["endpoints"][0]
listed = ep["supported_parameters"]
bad = []
for key in body:
if key in SKIP:
continue
if key not in listed:
bad.append(key)
elif key == "input_references" and listed[key].get("max", 0) == 0:
bad.append(key)
return bad
if __name__ == "__main__":
body = {"model": "google/imagen-4-fast", "prompt": "a tin", "quality": "high"}
print(unsupported(body["model"], body))
Building request bodies
Keep one body builder per model id and let it add optional fields only when the endpoint record lists them. A shared body with quality: "high" works on Ideogram and ChatGPT Image rows and fails on Flux and Seedream rows. Failed requests are not billed, but they still use a round trip, so the check is cheaper than discovering the rejection at send time.
Capability descriptors have three types: an enum is a list of allowed strings, a range is any integer between a minimum and a maximum, and a boolean means the field is accepted when present.
Log the full error body on every 400. It names the parameter that failed, which is quicker to act on than the status code alone. If you see it on a model you did not change, the catalog row may have changed, so fetch the endpoint record again and update your builder from it.
Sources
Related posts
More in Developers
- Sume image n: docs say up to 10, every catalog row says 4 or less
The Image API docs say n is 1 to 10, but each catalog row publishes its own ceiling: 4 on most, 1 on Grok Imagine. Cost is cost_usd times n. Table with prices.
- Sume job 404 for an id you created: check which member's key made it
A 404 on GET /v1/jobs/{id} can mean the job belongs to another member or workspace. A Python helper separates unknown from not visible.
- job.canceled: the third Sume terminal event your handler forgets
Sume sends job.completed, job.failed and job.canceled and nothing else. A handler that covers only two leaves canceled jobs open. Route all three, 204 the rest.
- Sume MCP first call: mcp_health must say mcp_oauth, then tools_list
After adding the Sume connector, call mcp_health and check authenticated.auth_source is mcp_oauth. Then call tools_list to see which tools your grant exposes.
Written by Sume