Agent Completions 404 agent_run_not_found: which id to poll
A 404 agent_run_not_found means the id is not an Agent Completion run of your account, often an Action or Format run id. Poll, list and cancel agrun_ runs.

A 404 agent_run_not_found from Sume's Agent Completions endpoints means the id you polled is not a completion run in your account: it is unknown, it belongs to someone else, or it is an Action or Format run id, which will not resolve here. Poll the id from the 202 receipt of POST /v1/agent/completions, the one that starts with agrun_.
This post covers the three run surfaces, the poll and cancel calls, and a loop that stops at the right time.
Why does a Format or Action run id return 404?
Sume has three ways to run its agent, and they share a receipt shape but not an id space. The docs put it this way: a Format stores how to do something, a scheduled Action stores what to do and when, and an Agent Completion stores nothing because you send the task on every call. Each starts from its own endpoint, and a run created by one is read through that one's endpoints.
So when a worker queue passes ids around, carry the surface with the id, or poll GET /v1/agent-runs/{id} only for ids you got from POST /v1/agent/completions.
| Surface | Start with | Poll a completion id here? |
|---|---|---|
| Format | POST /v1/formats/{handle}/{slug}/runs | No, 404 |
| Scheduled | POST /v1/actions/{handle}/{slug}/runs | No, 404 |
| Agent Completions | POST /v1/agent/completions | Yes, GET /v1/agent-runs/{id} |
How do you poll a completion?
Statuses are queued, processing, completed, failed and canceled, the same as Action runs. The receipt also carries a status_url; the docs say to poll it until next_action stops being poll_status. A completed run fills output, with the closing text in output.text and generated media in output.images, output.videos, output.audio and output.files, as durable media.sume.com URLs. Back off between polls, since a run opens a sandbox and may generate media.
import os
import time
import requests
HEADERS = {"Authorization": f"Bearer {os.environ['SUME_API_KEY']}"}
DONE = {"completed", "failed", "canceled"}
def wait_for_run(run_id, every=5.0, limit=1800.0):
start = time.monotonic()
while time.monotonic() - start < limit:
r = requests.get(
f"https://api.sume.com/v1/agent-runs/{run_id}",
headers=HEADERS, timeout=30)
r.raise_for_status()
run = r.json().get("data", r.json())
if run["status"] in DONE:
return run
time.sleep(every)
every = min(every * 1.5, 30.0)
raise TimeoutError(run_id)How do you cancel or list runs?
To stop a run in flight, POST /v1/agent-runs/{id}/cancel; the receipt's cancel_url is the same address. GET /v1/agent-runs lists your completions, newest first. A local timeout in your poller does not cancel anything on Sume, so a loop that gives up should also call cancel if the run is still not terminal, or the run keeps working under its spend cap.
Two more causes of surprise. A key created before Agent Completions shipped has no agent_completions:* scope and gets 403 insufficient_scope, and scopes cannot be added to an existing key, so create a new one. And if you want a push instead of a poll, communication.webhook_url takes a public HTTPS URL notified at a terminal status (Run webhooks).
What does the receipt tell you?
The 202 receipt is the record to keep. The fields below are the ones that matter when you debug a 404 or a stuck run.
| Field | What it is | Use it for |
|---|---|---|
| id | The agrun_ run id | Polling and canceling |
| object | agent.run | Telling it apart from other run types in logs |
| model | sume-agent, the only value | Nothing; omit model on requests |
| thread_id | The thread this run used | Finding the run in the product; every completion gets a fresh one |
| status_url, cancel_url | Ready-made addresses | Poll and cancel without building URLs |
| usage | Spend cap in micros, then recorded spend | Reconciling cost per run |
If a 404 persists for an id you are sure came from the completions endpoint, check which API key made the call. The docs say a run belonging to another account returns the same 404, so a worker using a key from a different account than the submitter will see exactly this.
Sources
Related posts
More in Developers
- Agent Completions 400: generation_spend_cap_usd is required
POST /v1/agent/completions returns 400 invalid_request without generation_spend_cap_usd. It has no default: why, how to size it, and what the receipt echoes.
- Agent Completions input_image: send a photo in messages[]
Send an image to Sume's Agent Completions as an input_image content part inside messages[], merge it with attachments, and get a caption back as typed output.
- AI API budget ran out: which error? Claude 400 and 429, Sume 402
Claude returns 429 enforced_spend_limit_reached at the tier cap and 400 for a limit you set. Sume returns 402 at create and a failed run at the cap.
- AI image API 429s: queue_full vs rate_limited, and how to retry each
Sume returns 429 for two different reasons. rate_limited means back off; queue_full means wait for jobs to finish. A Python retry that treats them differently.
Written by Sume