Ideogram 4.5 edit in TypeScript: handle 200, 202 and 502 on Sume
One fetch helper for POST /v1/images with Ideogram 4.5: return the URL on 200, poll status_url and result_url on 202, and throw the error body on 502.

An Ideogram 4.5 edit through Sume's POST /v1/images has three outcomes you must branch on: 200 with the image in data[0].url, 202 with a job envelope you poll, and 502 with an error body when the job failed inside the wait. The helper below returns the URL for the first two and throws on the third.
Ideogram announced 4.5 on 2026-09-30 as an edit model meant for multi-turn work (Ideogram on X, read 2026-10-05). Multi-turn means a loop of calls, so the status handling has to be right once and reused.
What does the helper look like?
It needs Node 18 or later for global fetch, a SUME_API_KEY in the environment, and a public HTTPS URL for the source picture. The first input_references entry is the image Ideogram edits, per the Image API docs.
const API = "https://api.sume.com/v1";
const H = {
Authorization: `Bearer ${process.env.SUME_API_KEY}`,
"Content-Type": "application/json",
};
const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));
export async function edit(src: string, prompt: string, key: string) {
const res = await fetch(`${API}/images`, {
method: "POST",
headers: { ...H, "Idempotency-Key": key },
body: JSON.stringify({
model: "ideogram/ideogram-v4.5",
quality: "low",
prompt,
input_references: [src],
}),
});
const body: any = await res.json();
if (res.status === 200) return body.data[0].url as string;
if (res.status !== 202) throw new Error(JSON.stringify(body.error ?? body));
for (let wait = 2000; ; wait = Math.min(wait * 2, 15000)) {
await sleep(wait);
const st: any = await (await fetch(body.status_url, { headers: H })).json();
if (st.status === "failed" || st.status === "canceled") throw new Error(st.status);
if (st.status === "completed") break;
}
const out: any = await (await fetch(body.result_url, { headers: H })).json();
return (out.result?.artifacts ?? out.artifacts)[0].url as string;
}
Why does the status code decide the path?
The route defaults to mode: "sync" with a 30 second wait, so most small edits answer 200. If the job outlives the wait, or you sent mode: "async" or "webhook", you get 202 with the current job envelope, and you read the images from the job result. A job that fails terminally inside a sync wait is a 502 with the error envelope, not a 202 to poll, so a 502 is a decision for you, not a transport blip.
| Status | Meaning | Helper action |
|---|---|---|
| 200 | Done inside the 30 s wait | Return data[0].url |
| 202 | Wait expired, or async or webhook mode | Poll status_url, then read result_url |
| 502 | Terminal failure in sync mode | Throw the error object; check retryable |
| 402 | insufficient_credits | Stop and add funds |
What should I do with a 502?
Read the envelope. It carries code, message, retryable and next_action, plus status_url and result_url for the job that failed. The docs example is input_media_unreachable with retryable: false and next_action: "fix_input": the source URL could not be downloaded, so retrying the same request does the same thing. Only retry when retryable is true, and keep the same Idempotency-Key only if the payload is unchanged.
Where does the result live after a 202?
The Jobs and results page shows a completed job with result.artifacts[], each with a url. The helper reads result.artifacts and falls back to a top-level artifacts in case the result endpoint returns the bare result; check the real body once with curl against your own job and delete the fallback you do not need. Add a line or two of your own handling for a 202 whose status_url is missing, since the helper assumes the envelope has it.
Poll with backoff and stop on completed, failed or canceled. Do not submit the same paid request again because your process timed out; the docs say to poll the job instead. For longer chains, a webhook that fires on job.completed removes the loop altogether, as in chaining Ideogram edits with webhooks.
What does one call cost?
At Sume's list x 1.25, an Ideogram 4.5 edit is $0.0375 at low, $0.075 at medium (the default) and $0.275 at high, for any size. The helper pins low, which suits drafts; change one string for finals. Read usage.cost from a 200 body for the billed figure per call; on a 202, the docs point to billable_amount_usd_micros in the submit envelope.
How do I run many edits at once?
Call the helper from Promise.all in small groups rather than all at once. Sume admits a limited number of generations per plan, and past the queue it answers 429 queue_full; the generation admission docs list the counts. Treat a 429 as a signal to wait and retry the same request with the same Idempotency-Key, not as a failure of the edit.
Give each call a stable key built from your own ids, for example ${assetId}-${pass}, so a retry after a crash returns the first job and does not bill twice.
Sources
Related posts
More in Developers
- Ideogram 4.5 on Sume does not accept output_format
Ideogram 4.5's output format is chosen by the provider on Sume. Which other image ids take png, jpeg or webp, and how to convert after the fact in Python.
- Ideogram 4.5 transparency claim vs Sume's background field
Higgsfield lists transparent backgrounds for Ideogram 4.5. On Sume, background works only on ChatGPT Image 2.5; other models need RMBG or Image 1.0.
- Image API changes in October 2026: what to do and when
October 2026 image API changes: gpt-image-1 shuts down 2026-10-23, three more OpenAI ids on 2026-12-01, GPT Image 2.5 ships, and Sume retires Image 1.0.
- Retry an image edit after a timeout: same key, same payload
After a client timeout on an image edit, resend the same payload with the same Idempotency-Key. If you change the prompt, change the key.
Written by Sume