Rust reqwest: POST /v1/images on Sume and branch on 200 or 202
Call Sume's image API from Rust with reqwest::blocking and serde_json; one 40-second client timeout and a match on 200, 202 and errors.

The blocking client is the shortest path for a CLI tool; use the async client inside a larger service.
The request is the same in every language: POST https://api.sume.com/v1/images with a bearer key from SUME_API_KEY, a JSON body with model, prompt and aspect_ratio, and a client timeout above the route's 30-second wait. The route defaults to mode: "sync", so the status code decides what you do next (docs read 2026-10-07):
Status codes to branch on
| Status | Meaning | What the code below does |
|---|---|---|
| 200 | Image finished inside the wait; data[].url holds the file | Prints the result |
| 202 | Wait expired (or mode is async or webhook); body is a job envelope with status_url and result_url | Prints the envelope; poll status_url and read result_url |
| 502 | The job failed inside the wait; error has code, retryable, next_action | Prints the error |
| 400, 404 | unsupported_parameter, or model_not_found | Prints the error |
Rust code
Add reqwest = { version = "0.12", features = ["blocking", "json"] } and serde_json = "1" to Cargo.toml, then SUME_API_KEY=... cargo run.
use serde_json::{json, Value};
use std::{env, time::Duration};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let key = env::var("SUME_API_KEY")?;
let client = reqwest::blocking::Client::builder()
.timeout(Duration::from_secs(40))
.build()?;
let res = client
.post("https://api.sume.com/v1/images")
.bearer_auth(key)
.json(&json!({
"model": "bytedance-seed/seedream-5-lite",
"prompt": "matte ceramic mug on a white sweep, soft shadow",
"aspect_ratio": "16:9"
}))
.send()?;
let status = res.status().as_u16();
let text = res.text()?;
match status {
200 => {
let v: Value = serde_json::from_str(&text)?;
println!("done: {}", v["data"][0]["url"]);
}
202 => println!("queued, follow status_url: {text}"),
_ => println!("error {status}: {text}"),
}
Ok(())
}Notes
The response is read as text first, so an error body that is not an image result never fails JSON parsing.
env::var("SUME_API_KEY")? fails fast when the key is missing instead of sending an unauthenticated request.
One bytedance-seed/seedream-5-lite image is $0.04375 billed (list $0.035 x 1.25). Prices here are Sume's list-times-1.25 figures. The catalog states the billable formula as "list × 1.25 → ceil usd cents", so treat the dollar amounts as the pre-rounding value and read the exact charge from billable_amount_usd_micros in the submit envelope. Failed or cancelled generations are not billed.
Sources: Sume Image API docs and Jobs and results (read 2026-10-07).
Sources
Related posts
More in Developers
- Scan your repo for retiring Google image and TTS ids (Python)
A 30-line Python scanner that finds Imagen 4, Nano Banana and Gemini TTS preview ids in your files and prints the replacement Google names for each one.
- Seedance 2.5 estimate vs usage.cost: reconcile a job in Node
Compute the Seedance 2.5 price from width, height and seconds, submit one job to Sume, and compare it with usage.cost on the poll. A runnable Node 18 script.
- Semantic Kernel .NET defaults to gpt-image-1: it fails Oct 23
The .NET OpenAI connector in Semantic Kernel defaults to gpt-image-1, which OpenAI removes Oct 23, 2026. What breaks, and a C# call to Sume that does not.
- SHA-256 the batch body into the Sume idempotency key for bulk chunks
Derive each bulk chunk's Idempotency-Key from a hash of its items so replays reuse the queue and edited rows get a new key instead of a 409 conflict.
Written by Sume