Pick the cheapest Sume image row for a ratio and 3 refs (Python)
A 24-line Python script reads GET /v1/images/models and the endpoints route, filters by aspect ratio and reference count, and sorts by billed price.

To find the cheapest Sume image row that takes a given aspect ratio and a given number of reference images, call GET /v1/images/models, keep the rows whose aspect_ratio list contains your ratio and whose input_references max is at least your count, then read each survivor's price from its endpoints route and sort. The script below does exactly that in under 30 lines of standard-library Python.
New image rows keep arriving, and a row you picked last month may no longer be the cheapest one that fits. The catalog descriptors and the pricing lines are published for this reason: the Image API docs say you can find what a model supports before you call it, and that the endpoint pricing lines are what Sume charges.
The script
It needs only SUME_API_KEY in the environment. The list route gives supported_parameters for each model; the endpoints route gives pricing, a list of billable lines. Image rows publish one output_image line in dollars per image, so the first entry is the one to read. The docs show the endpoints response without a data wrapper, and the script tolerates either shape.
import json, os, urllib.request
BASE = "https://api.sume.com"
KEY = os.environ["SUME_API_KEY"]
def get(path):
req = urllib.request.Request(BASE + path, headers={"Authorization": "Bearer " + KEY})
with urllib.request.urlopen(req, timeout=30) as r:
return json.load(r)
def pick(ratio, refs):
rows = []
for m in get("/v1/images/models")["data"]:
sp = m["supported_parameters"]
ratios = sp.get("aspect_ratio", {}).get("values", [])
max_refs = sp.get("input_references", {}).get("max", 0)
if ratio in ratios and max_refs >= refs:
ep = get("/v1/images/models/" + m["id"] + "/endpoints")
ep = ep.get("data", ep)
rows.append((ep["endpoints"][0]["pricing"][0]["cost_usd"], m["id"]))
return sorted(rows)
for price, model in pick("4:5", 3):
print(f"{price:.5f} {model}")What it printed against the catalog I read
I did not call the live API for this post. I ran the same filter over the catalog code on origin/main, which builds the descriptors and prices that the routes publish, for a 4:5 ratio with 3 references. Thirteen rows qualified on 2026-10-10. Rows that do not list 4:5 (Grok Imagine, Higgsfield Soul, Imagen 4) and rows that take no references (Recraft V4, Qwen Image Max, Imagen 4) drop out.
| Row | Billed per image |
|---|---|
| Qwen Image | $0.025 |
| Seedream 4.0 | $0.0325 |
| FLUX.2 Pro | $0.0375 |
| Seedream 5.0 Lite | $0.04375 |
| Seedream 4.5 | $0.05 |
| FLUX.2 Flex | $0.0625 |
| ChatGPT Image 2.5 and 2.5 Sunburst | $0.065875 each |
| Ideogram V3 and Ideogram 4.5 | $0.075 each |
| Nano Banana 2.1 | $0.10 (1K) |
| Nano Banana Pro | $0.1875 (1K) |
| ChatGPT Image 2 | $0.26375 |
Caveats before you trust the order
The price line is the default tier. Nano Banana 2.1 is $0.10 at 1K but $0.20 at 4K, and ChatGPT Image 2.5 is quoted at high quality and 1024 square, with other sizes and qualities admitted at their own estimate. Ideogram 4.5 is quoted at its default medium quality; low is cheaper and high is more expensive. If your job uses a non-default tier, add that tier's price to the table by hand.
Cheapest is not the same as right. The filter says nothing about how a row handles your product photo or your headline text. Use it to cut 19 rows to a shortlist, then generate one image on each of the top three and look at them.
- Read the descriptor
maxfor references, not the docs prose, because it can change per row. - Treat a row missing from the list as unavailable: the catalog hides rows whose provider is not configured.
- Cache the table for the length of one batch, not for a month.
Make the filter fit your pipeline
Add n to the filter if you want several variants per call: Grok Imagine's n range is 1 to 1, so a four-variant job needs four calls on that row. Add resolution if you need a tier: only five rows list it. Add quality to keep GPT and Ideogram rows that expose a quality ladder.
Keep the output as data rather than printing it. A nightly job that writes the sorted rows to a file lets you diff today's shortlist against yesterday's and notice when a price moves or a row appears.
Sources
Related posts
More in Developers
- Pick the highest resolution a Sume video model lists (Python)
Sume's catalog row is now the one resolution list for both video endpoints. A short Python helper reads supported_resolutions and steps down instead of failing.
- Port a fal queue submit and poll loop to Sume /v1/videos in Python
A fal queue client posts to queue.fal.run, polls a status URL and fetches a result. The Sume version is 21 lines of Python on /v1/videos. Field map, traps.
- Port an ElevenLabs text-to-speech call to Sume TTS 1.0, field by field
ElevenLabs puts the voice in the URL; Sume TTS 1.0 takes it in the body and rejects model_id. A field map and a tested mapper function.
- Preview a HyperFrames composition as PNG stills with the Sume API
POST /v1/hyperframes-previews returns 1-6 PNG stills of a composition without rendering an MP4. Request shape, polling, and what the frames are not.
Written by Sume