job_scope_forbidden: why an agent run cannot list every Sume job
A thread-bound Sume credential lists only its own thread's jobs, and unattended runs cannot ask for the whole workspace. What to use instead.

If an unattended agent run asks Sume for scope=workspace when listing jobs, it gets job_scope_forbidden. That is by design. A Studio Agent turn sees only the jobs its own thread created, and only an interactive turn may widen to the whole workspace. An ordinary API key, in contrast, defaults to the workspace. So the same GET /v1/jobs call can return different sets depending on which credential made it.
The fix is not a workaround. It is choosing the credential that matches the question you are asking.
What does the spec say about scope?
The Sume OpenAPI spec describes the list route this way: scope defaults to thread for a thread-bound credential and to workspace for an ordinary API key. run_id narrows to one automation run without widening past the thread. thread_id may only name the caller's own thread, so it never widens a bound credential.
| Caller | Default scope | Can ask for workspace? |
|---|---|---|
| Ordinary API key | workspace | Already is |
| Thread-bound credential, interactive turn | thread | Yes, with scope=workspace |
| Thread-bound credential, unattended run | thread | No, job_scope_forbidden |
What should an agent do instead?
Ask about what it made. Keep the job ids your own run created and read them by id, or list with the default thread scope. Reporting across the workspace is a job for a service that holds an ordinary API key, not for an unattended run.
- Store each job id when you submit it.
- Use
run_idto narrow within a run. - Do not retry a scope error; it will not change.
What does the call look like?
A default-scope list that works for either credential kind:
import os, requests
H = {"Authorization": "Bearer " + os.environ["SUME_API_KEY"]}
r = requests.get("https://api.sume.com/v1/jobs", headers=H,
params={"status": "completed", "limit": 20}, timeout=30)
print(r.status_code)
if r.ok:
for job in r.json()["data"]["jobs"]:
print(job["id"], job["type"], job["status"])
else:
print(r.text[:300])
Where do audit lists belong?
On a service with an ordinary key, paging through status filters as in listing failed audio jobs. For job ids and hosted artifacts as a portability habit, see keeping a TTS pipeline portable.
Sources
Related posts
More in Agents
- Kilo scheduled sessions vs a Sume schedule for recurring renders
Kilo v7.8.3 reports a session waiting on a wakeup or cron task as scheduled. A Sume schedule lives server-side; use it when renders must run unattended.
- OpenAI Dots x Runway: brief a dot, it plans shots. The Sume loop
Runway's Oct 1 changelog lists OpenAI Dots x Runway for all plans: brief a dot, it plans shots, Runway shoots. The same loop with Sume MCP tools.
- Qwen3.8-Omni-Flash for audio agents: tool access
Qwen3.8-Omni-Flash is an omnimodal model for agents. Whatever model you pick, give it Sume's hosted MCP tools and check tools_list before any paid call.
- script_run or Agent Completion: which for a GPT-6.1 Sol agent?
A GPT-6.1 Sol coding agent can call Sume via MCP script_run or Agent Completions. Which fits fan-out of known calls, and which fits open-ended tasks.
Written by Sume