Generate 100 images with the Sume Image API: async jobs and polling

Submit each image with mode async, collect job ids, then poll status. Each job bills only if it completes; failed jobs use no credits.

5 min readSume
All posts

Use mode: "async" for each request, keep the job ids, and poll GET /v1/jobs/{id}/status until terminal is true. For a run of 100 images on qwen/qwen-image at $0.025 billed each, the total is $2.50 if all jobs complete. A job that fails or is cancelled uses no credits, per the Image API docs.

Plan the run

n is capped at 4 per call on most rows and at 1 on x-ai/grok-image, so 100 images can be 25 calls of n: 4 or 100 calls of n: 1. One call is one job, so batching with n reduces your job count. The arithmetic below uses the list x 1.25 formula, with each job rounded up to the cent; the Grok row is the only one where that matters, since a single 2.5 cent image bills as 3 cents.

Sume image catalog rows (list from the Sume repo, billed = list x 1.25), read 2026-10-13
RowBilled per image100 imagesCalls at max n
qwen/qwen-image$0.025$2.5025
x-ai/grok-image$0.025 list x 1.25; $0.03 per n=1 job$3.00100
black-forest-labs/flux.2-pro$0.0375$3.7525
google/nano-banana-2.1 (1K)$0.10$10.0025

Submit and poll

The script submits all jobs first and then polls them in a loop. It prints the final sume_status for each. Fetch result_url for completed jobs to read the image URLs. Add an Idempotency-Key header per job if your runner can retry the submit step.

import os, time, requests

H = {"Authorization": f"Bearer {os.environ['SUME_API_KEY']}"}
jobs = []
for i in range(25):
    r = requests.post(
        "https://api.sume.com/v1/images",
        headers=H,
        json={"model": "qwen/qwen-image", "prompt": f"flat icon set {i}", "n": 4, "mode": "async"},
        timeout=30,
    )
    r.raise_for_status()
    body = r.json()
    jobs.append(body.get("data", body)["status_url"])

for url in jobs:
    while True:
        s = requests.get(url, headers=H, timeout=30).json()
        s = s.get("data", s)
        if s.get("terminal"):
            print(url, s.get("sume_status"))
            break
        time.sleep(s.get("next_poll_after_seconds") or 3)

Before a big run

  • Run 3 jobs first and read the result shape.
  • Check your plan's concurrency before you fire 25 at once.
  • Cap the polling loop with your own deadline; a client timeout does not cancel the job.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume