Job id or run id: which Sume endpoint and helper do you poll?

A job_ id is polled at /v1/jobs/:id with waitForJob. An arun_ id is a Format, Action or Agent run, polled with waitForRun and a family argument.

5 min readSume
All posts

Look at the prefix. An id that starts with job_ is a generation job. You read it at GET /v1/jobs/:id/status and fetch the result at GET /v1/jobs/:id/result. In the TypeScript SDK you wait for it with waitForJob. An id that starts with arun_ is a Format, Action or Agent run. You read it at /v1/format-runs, /v1/action-runs or /v1/agent-runs, and you wait for it with waitForRun, which needs a family argument that names the one you mean.

Why the two families exist

The two ids come from different submit calls, and they are not interchangeable. The families also differ in how they end. A job ends in completed, failed or canceled, while a run can also end in skipped, for example when an active run policy declines to start another one. If you pass a run id to a job route you get a not-found error, not a status. This is the most common first-day mistake in integrations that submit both a direct generation call and a Format run, because both responses carry a request id and a status URL.

  • Jobs are the paid generation calls such as an image or avatar generate request. They have the statuses queued, processing, completed, failed and canceled.
  • Runs are the higher level Format, Action and Agent runs. Their terminal statuses are completed, failed, canceled and skipped, and they report an outcome of ok, degraded or error.
  • A Format run may start several generation jobs inside it. You still poll the run, not the inner jobs, unless the run receipt tells you to do otherwise.

The routing table

Use this table when you hold an id and have to choose the call.

Poll route and SDK helper by id family (read 2026-10-05)
Id prefixPoll routeSDK helperDefault client timeout
job_GET /v1/jobs/:id/statuswaitForJob20 minutes
arun_ (Format)GET /v1/format-runs/:idwaitForRun with family format10 minutes
arun_ (Action)GET /v1/action-runs/:idwaitForRun with family action10 minutes
arun_ (Agent)GET /v1/agent-runs/:idwaitForRun with family agent10 minutes

What each helper does for you

waitForJob polls no faster than every 2 seconds and obeys next_poll_after_seconds when the server asks for a longer pause. waitForRun tolerates up to 6 transient failures before it throws. A Format run can also be watched live with subscribeFormatRun, which sends an automatic UUID idempotency key unless you pass null to send none.

Pick the route from the id

The function below picks the poll path from the id. It runs as is and needs no network, so you can drop it into a router or a test.

def poll_path(entity_id: str) -> str:
    if entity_id.startswith("job_"):
        return f"/v1/jobs/{entity_id}/status"
    if entity_id.startswith("arun_"):
        # the run family comes from the submit route you called
        raise ValueError("arun_ ids need the family: format, action or agent")
    raise ValueError("unknown id prefix: " + entity_id[:5])

def run_path(family: str, run_id: str) -> str:
    routes = {"format": "format-runs", "action": "action-runs", "agent": "agent-runs"}
    return f"/v1/{routes[family]}/{run_id}"

print(poll_path("job_123"))
print(run_path("format", "arun_123"))

Store the family with the id

Store the family next to every run id when you save it. The prefix alone does not say whether a run is a Format, an Action or an Agent run, and waitForRun will not guess. Also keep the polite behaviour the docs ask for. Use backoff, stop on a terminal status, and never submit the paid request again only because your own process timed out.

What changes after the first poll

Three more differences matter once the first poll works. They decide how you finish the loop, what you do with a result, and whether you can rely on a webhook at all.

  • A finished job gives you artifacts shaped as {id, url, type, content_type}. A finished run gives the same fields plus size_bytes, width, height, duration_ms and checksum_sha256, so a run result can be verified without a second download.
  • Job webhooks are job.completed, job.failed and job.canceled. Run webhooks are format.run.terminal, action.run.terminal and agent.run.terminal. Canceled and skipped runs send no webhook, so a poll is the only way to see them.
  • Retrying a failed run needs a new idempotency key, while a job retry after a network error should reuse the original key. Treat the two families separately in your retry code, and log which family every id came from.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume