Node fetch to Sume with Ideogram 4.5: branch on status 200 or 202
POST /v1/images returns 200 with data[].url or 202 with a job envelope. A Node 22 fetch sample that checks res.status, with a 40 second abort signal.

POST /v1/images blocks for up to 30 seconds. If the image is ready it answers 200 with data[].url; if not, it answers 202 with the standard job envelope (data.job.id, status_url, result_url). The image docs are blunt about it: examine the status code, not the body shape. Slow settings such as 4K, high quality and large n are the likeliest to degrade to 202.
Ideogram 4.5 at quality: "high" and resolution: "2K" is a good test, because it is the kind of request that may land on either side.
Node 22 sample
The abort signal is 40 seconds, longer than the 30 second server wait, so you see the 202 instead of cutting the call yourself. The last two lines run the function against fake responses so you can try both branches with no key.
export async function submit(fetchFn = fetch) {
const res = await fetchFn("https://api.sume.com/v1/images", {
method: "POST",
headers: {
"x-api-key": process.env.SUME_API_KEY ?? "",
"content-type": "application/json",
"idempotency-key": "banner-autumn-v1",
},
body: JSON.stringify({
model: "ideogram/ideogram-v4.5",
prompt: "Autumn sale banner, bold serif headline",
quality: "high",
resolution: "2K",
}),
signal: AbortSignal.timeout(40_000), // the route itself waits up to 30 s
});
const body = await res.json();
if (res.status === 200) return { kind: "ready", urls: body.data.map((i) => i.url) };
if (res.status === 202) return { kind: "job", jobId: body.data.job.id, statusUrl: body.data.status_url };
throw new Error(`HTTP ${res.status}: ${body?.error?.code ?? "unknown"}`);
}
const fake = (status, body) => async () => new Response(JSON.stringify(body), { status });
console.log(await submit(fake(200, { data: [{ url: "https://media.sume.com/a.png" }] })));
console.log(await submit(fake(202, { data: { job: { id: "job_1" }, status_url: "https://api.sume.com/v1/jobs/job_1/status" } })));After a 202
Hand the job id to a poller. In TypeScript, waitForJob in @sume-com/sdk reads /v1/jobs/{id}/status with a 2 second floor and returns the terminal job. Without the SDK, poll status_url, honor next_poll_after_seconds, and fetch result_url only when the job is completed; fetching it earlier gives 409 job_not_completed.
Details worth keeping
- Keep the
Idempotency-Keystable across your own retries, so a retried POST does not create a second image job. - Send
x-api-keyonly, never alongsideAuthorization; both together get401 unauthorized. - Do not set
stream: true,seedoroutput_compressionfor these models: they return400rather than being ignored.
Sources
Related posts
More in Developers
- Node fetch worker pool: submit transcription jobs with retry-after
A 30-line Node 18+ worker pool that posts Sume STT jobs, sleeps for retry-after on 429, and sends an Idempotency-Key per clip. Tested against a stub.
- Nova Canvas boto3 read timeout vs Sume's 30 second wait and 202
The AWS SDK read timeout is 60 s and Amazon suggests 300 s for Nova Canvas. Sume's /v1/images waits 30 s, then returns a 202 job. Handle both in Python.
- Nova Canvas cfgScale 1.1 to 10 vs Sume: no guidance field
Nova Canvas has a cfgScale from 1.1 to 10, default 6.5. Sume rejects fields a model does not list. How to get the same effect with wording and model choice.
- Nova Canvas returned fewer images than asked: Sume n and data length
Nova Canvas can return fewer images than numberOfImages when moderation blocks some. How to count what you got and what you paid for on Sume.
Written by Sume