Check your image cost table against Sume /v1/images/models cost_usd
Read pricing lines from GET /v1/images/models/{id}/endpoints and compare cost_usd with your own table before a batch. Sume lines already include its margin.

Before you run a large image batch, read the price from the API rather than from a spreadsheet. GET /v1/images/models/{model_id}/endpoints returns, for each endpoint, a pricing list with billable, unit and cost_usd. Sume's docs say those lines already include the Sume margin, so you pay cost_usd times n for n images. The Python script compares each line with the figure in your table and prints ok or DIFFERS.
What the endpoint returns
The list of models at GET /v1/images/models has a link to the endpoints route for each id. Each endpoint object names a provider slug and has a pricing array, for example one line with billable output_image, unit image and cost_usd 0.033 for a model in Sume's docs. The script flattens those lines.
| Field | Meaning |
|---|---|
| endpoints[].provider_slug | Which backend the line belongs to |
| pricing[].billable | What is counted, such as output_image |
| pricing[].unit | Unit of the count, such as image |
| pricing[].cost_usd | Price per unit in USD, margin included |
| Your total | cost_usd x n images |
A worked comparison
The sample table expects google/nano-banana-2.1 at 0.10 per image. That is the Sume list price for a 1K image. For 40 images the expected total is 40 x 0.10 = $4.00. If the endpoint prints a different cost_usd, the script says DIFFERS from 0.1, and you should find out whether the price changed or your table was for another size before you spend $4.00 or $40.00.
Prices for one model can differ by size. Nano Banana 2.1 is $0.075 at 0.5K, $0.10 at 1K, $0.15 at 2K and $0.20 at 4K in Sume's price list, so a table with one number per model is already a source of drift.
import json, os, urllib.request
EXPECTED = {"google/nano-banana-2.1": 0.10} # USD per 1K image, from your own cost table
def endpoint_prices(model_id):
req = urllib.request.Request(f"https://api.sume.com/v1/images/models/{model_id}/endpoints",
headers={"Authorization": "Bearer " + os.environ["SUME_API_KEY"]})
with urllib.request.urlopen(req) as r:
endpoints = json.load(r)["endpoints"]
return [(e["provider_slug"], line["billable"], line["unit"], line["cost_usd"])
for e in endpoints for line in e["pricing"]]
for model, expected in EXPECTED.items():
for slug, billable, unit, cost in endpoint_prices(model):
flag = "ok" if abs(cost - expected) < 1e-9 else f"DIFFERS from {expected}"
print(model, slug, billable, unit, cost, flag)Make it a gate
The script exits cleanly even when a line differs. In a pipeline, change the print to a non-zero exit so a batch stops when the API and your table disagree. Compare with a small tolerance, as the sample does, because floating-point values from JSON can carry a trailing digit.
Billing for images is per image, not per token. Sume meters image models per image, and the token counts in the response are 0, so there is no token arithmetic to do.
A second use is catching a model alias. Sume accepts the bare Image Router ids as aliases for their org/slug equivalents, and retired ids run as their replacements, so a table keyed on an old id may price the wrong row. The endpoints route is read with the canonical id, which makes the comparison unambiguous.
Finally, record the date of the check with the result. A cost table that says it matched the API on a given day is much easier to trust at month-end than one with no history. Keep the expected prices in a file that you review with the finance owner, not in the script, so a change is a reviewed commit.
- Run the check on the same key as the batch.
- Store cost_usd in the job record.
- Re-read prices on a schedule, not once.
Sources
Related posts
More in Developers
- CI guard: fail the build when a new Sume pricing_skus key appears
A node:test file fetches GET /v1/videos/models and fails when a model uses a pricing_skus key your cost code cannot total. Wan, Omni and H3 rates in the table.
- Run an Agent Completion nightly from CI with curl and a spend cap
A 25-line bash job that starts a Sume Agent Completion with a cap and an idempotency key, polls the receipt, and fails the build unless the run completed.
- Egress firewall for a Claude agent in CI: Sume hosts to allow
Claude Agent SDK v0.2.164 hardens CI egress firewalls. Which Sume hosts a render job needs: api.sume.com, mcp.sume.com and media.sume.com, and what each is for.
- Claude Code 2.1.295 MCP changes: a checklist for Sume
Three MCP changes in Claude Code 2.1.295 (Oct 8) and what each means for a connection to Sume's hosted server. A short table to run through after upgrading.
Written by Sume