Seedream failed generations: free on that route, free on Sume too
OpenRouter's Seedream 5.0 Flash page says failed generations are not charged. Sume's Image API docs say failed or cancelled generations get no charge either.

Both routes say a failed image is not billed. OpenRouter's Seedream 5.0 Flash page (read 2026-10-05) states that failed generations are not charged. Sume's Image API docs state that completed generations get the full charge, and that failed or cancelled generations get no charge. The part that differs is what your code sees when a generation fails.
Billing rules compared
Only what each page says is listed.
| Route | Failed generation | Source |
|---|---|---|
| OpenRouter, Seedream 5.0 Flash | Not charged | OpenRouter model page |
| Sume Image API | No charge; request returns 502 | Sume docs, Billing and cancellation |
| Sume, client disconnect | Treated as a failed generation, no charge | Sume docs |
| Sume, completed generation | Full endpoint price; pay cost_usd x n | Sume docs |
What your code sees on Sume
A synchronous request waits up to 30 seconds. If the job fails terminally inside that wait, Sume returns 502 with an error envelope carrying code, message, retryable and next_action. If the wait budget runs out, or you send mode: "async", you get 202 with a job envelope instead, and you read the final state from the job's status and result URLs.
Branch on the status code, not the body shape. A 200 is images, a 202 is a job to poll, and a 502 is a terminal failure that you have not been billed for.
- Check
error.retryablebefore you resubmit. An unreachable reference URL isretryable: falsewithnext_action: fix_inputin the docs example. - In async and webhook modes the job is the answer, so read its status for the failure state.
A failure-safe request
This handles all three outcomes and prints the cost only when images came back.
import asyncio, os, httpx
async def main():
body = {"model": "bytedance-seed/seedream-5-lite", "prompt": "a red panda astronaut, studio lighting"}
headers = {"Authorization": f"Bearer {os.environ['SUME_API_KEY']}"}
async with httpx.AsyncClient(timeout=60) as c:
r = await c.post("https://api.sume.com/v1/images", headers=headers, json=body)
if r.status_code == 200:
print("cost", r.json()["usage"]["cost"])
elif r.status_code == 202:
print("poll", r.json()["data"]["status_url"])
elif r.status_code == 502:
e = r.json()["error"]
print(e["code"], e["retryable"], e["next_action"])
else:
print(r.status_code, r.text)
asyncio.run(main())Limits of this comparison
The OpenRouter page is one sentence, and we did not test what counts as a failure there (a moderation refusal, for example). Sume's docs say nothing different about that case, so for a refused or filtered image, check the job's final status and your usage line before you assume either way. For more on the Sume side, read why an unchanged retry is the wrong move.
Accounting tip
Tag each request with metadata so you can reconcile your own request log against Sume usage later. The Image API docs say Sume stores metadata on the job and does not send it to the provider. Then, at month end, compare the count of 200 responses with the count of billed images: they should match, and the 502s should not appear on the bill.
Sources
Related posts
More in Pricing
- Shortest Sume TTS job: a 1 cent minimum and a 95 cent ceiling
Sume TTS costs $0.0475 per 1,000 characters, 1 cent minimum, 95 cents for 20,000. Cost by length, and why 100 short lines cost more than one job.
- Six AI video test clips under $3 across four Sume models
Six short clips, four Sume video models, one prompt: the grid costs $2.58 and shows which model and resolution is worth a bigger top-up.
- Six instrumental holiday music beds for $0.78: one Lyria call per mood
Music Router bills $0.125 a generation, rounded to $0.13. Six moods for your Q4 ads cost $0.78, and a bed for each of 40 ad variants costs $5.20.
- Solo creator can't top up Sume? The team-wallet-only error
Sume top-ups are bought from a team wallet. If you see stripe_topup_team_only on a personal account, here is what the message means and the two ways out.
Written by Sume