GET /v1/jobs/:id returns 404 for a job your teammate's key created
A Sume job id can answer 404 not_found to your key though it exists: an API key reads only jobs its own member created, and only that member can cancel.

A 404 not_found on GET /v1/jobs/:id does not always mean the job id is wrong. Sume ties a job to its workspace and to the member whose key (or Agent turn) created it. An API key reads only the jobs that its own member created in the workspace of that key. If a teammate's key created the job, your key gets 404 not_found, the same answer as for an id that never existed.
This matters most when two people or two services share a workspace but use different keys. A job id pasted from a teammate's log will 404 for you, and the usual reaction (retry, then assume the job was deleted) wastes an hour. The fix is almost never in the retry loop. It is in which credential made the call, so the first debugging step is to compare the key that submitted the job with the key that is reading it.
What each caller can read
The rule in Jobs and results covers all of GET /v1/jobs/:id, /status, /result, /events and GET /v1/jobs. The table restates it.
| Caller | Reads | Everything else |
|---|---|---|
| API key | Jobs that its own member created in the key's workspace | 404 not_found |
| Studio Agent turn | Every job in the thread it runs on, whoever created it | 404 not_found for other members' jobs in other threads |
| Any caller | Nothing from another workspace | 404 not_found |
A thread_id filter cannot widen access
Adding thread_id to GET /v1/jobs makes the list smaller. It never increases what a key can read. So a key that lists with a teammate's thread_id still sees only its own member's jobs in that thread, which is often an empty list rather than an error.
Cancel follows the same owner rule
Only the member who created a job can cancel it. A different member's key is not the creator, so the cancel is not allowed. Do not build a shared "cleanup" service that cancels other people's queued jobs with its own key. Give each team service the key that submitted the work, or have the submitting service expose its own cancel route that your tools call.
Treat 404 as not visible, not gone
The sample reads a status and separates "this key cannot see it" from a transport or server error. It runs on Node 22 with a stub or the real API, and reads the key from the environment.
const base = process.env.SUME_API_BASE_URL ?? "https://api.sume.com/v1";
const key = process.env.SUME_API_KEY;
if (!key) throw new Error("SUME_API_KEY is not set");
async function readJob(id) {
const res = await fetch(`${base}/jobs/${id}/status`, {
headers: { "x-api-key": key },
});
if (res.status === 404) return { visible: false };
if (!res.ok) throw new Error(`status ${res.status}`);
return { visible: true, job: await res.json() };
}
const seen = await readJob(process.argv[2] ?? "job_123");
console.log(seen.visible ? seen.job.sume_status : "not visible to this key");Checklist when a job id 404s
- Confirm the key belongs to the workspace and the member that submitted the job. The submit response and your own logs should name the key that made the call.
- Do not resubmit a paid request because a read returned 404. Resubmitting creates a second job and a second charge unless you reuse the same
Idempotency-Key. - Store the job id next to the key id that created it, so a later reader knows which credential to use.
- Log the
request_idfrom the error envelope. It is safe to share with Sume support. - If a Studio Agent turn needs to read an API-fired job, run it in the thread the job was made in. A turn reads each job in its own thread.
For the full read matrix and every status route, see the Jobs and results page.
Sources
Related posts
More in Developers
- jq one-liner: export Sume bulk queue items to CSV by index
Turn the bulk queue receipt from a curl poll into CSV rows of index, status, run_id and error code with jq, then paste them next to your SKU column.
- Let browsers start Sume jobs through your server, not with your key
Browsers must never hold a Sume API key. A server route authenticates the user, checks the input, derives an Idempotency-Key and returns only the status URL.
- List every Format run: no GET /v1/format-runs, page per Format
GET /v1/format-runs does not exist. List runs per Format with limit, next_cursor and has_more, or keep your own index of the data.id you stored at create.
- How do I add a listen-to-this-page audio version with TTS?
Turn each article into an audio file with one async TTS job per page: a 9,000-character article costs 43 cents on Sume. What it does not replace.
Written by Sume