Jobs (REST)
The durable job queue lets apps enqueue work and trusted external workers pull it. Jobs are event-sourced (each transition emits a Job model event) and crash-safe (leases with a visibility-timeout reclaim). For the concepts and a worker walkthrough, see Durable Jobs & External Workers.
Endpoints
# App plane (user JWT)
POST /jobs # enqueue a job (any authenticated user)
GET /jobs/{id} # poll a job's status + result
# Worker plane (X-Worker-Token)
POST /jobs/lease # lease up to N eligible jobs
POST /jobs/{id}/heartbeat # extend a held lease
POST /jobs/{id}/complete # mark a leased job succeeded (+ result)
POST /jobs/{id}/fail # report a failed attempt
POST /jobs/{id}/progress # publish a live progress update (realtime)
# Admin plane (user JWT, Admin role)
POST /jobs/workers # mint a worker token
GET /jobs/workers # list worker tokens (metadata only)
DELETE /jobs/workers/{id} # revoke a worker tokenApp plane
POST /jobs — enqueue
Requires an authenticated user; the job is stamped with the caller's tenant. Idempotent when idempotencyKey is supplied (a repeat returns the existing job id).
// request
{ "queue": "media-gen", "kind": "video.generate",
"payload": { "prompt": "…" },
"idempotencyKey": "deal-42", // optional
"maxAttempts": 5, // optional, default 5
"priority": 0 } // optional, default 0
// 201 → { "id": "01J…" }400 if queue/kind is blank; 401 without auth. The same enqueue is available over GraphQL — mutation { enqueueJob(queue, kind, payload?, idempotencyKey?, maxAttempts?, priority?) } — and a workflow Job step (Workflows API).
GET /jobs/{id} — poll status
// 200
{ "id": "01J…", "queue": "media-gen", "kind": "video.generate",
"status": "succeeded", // queued | leased | succeeded | dead
"attempts": 1, "maxAttempts": 5,
"result": { "assetId": "…" }, // present once succeeded
"error": null }401 without auth; 404 if unknown — or if a tenant-bound user requests another tenant's job.
Worker plane
All worker-plane requests send X-Worker-Token: wkr_…. A token may only lease the queues it was minted for (403 otherwise); a missing/invalid/revoked token is 401.
POST /jobs/lease
// request
{ "queues": ["media-gen"], "capacity": 4, "visibilitySecs": 30 }
// 200
{ "jobs": [ { "id", "queue", "kind", "payload", "attempts", "maxAttempts", "leaseId" } ] }Each returned job carries a unique leaseId that must be echoed back to heartbeat/complete/fail. capacity is clamped to 1–100, visibilitySecs to 1–86400. An empty queues is 400.
POST /jobs/{id}/heartbeat
{ "leaseId": "…", "visibilitySecs": 30 } // → 204; 409 if the lease was lostPOST /jobs/{id}/complete
{ "leaseId": "…", "result": { "assetId": "…" } } // → 204; 409 if the lease is stalePOST /jobs/{id}/fail
// request
{ "leaseId": "…", "error": "provider rate limited", "retryable": true }
// 200 → retry scheduled with backoff
{ "outcome": "retry", "delaySecs": 5 }
// 200 → attempts exhausted / non-retryable
{ "outcome": "dead" }
// 409 → the lease is stale (no-op)POST /jobs/{id}/progress
Publish a live, ephemeral progress update — it fans out over realtime (it is not written to the durable event log). Also extends the lease (progress is a sign of life).
{ "leaseId": "…", "percent": 0.5, "message": "calling provider", "data": { … } } // → 204; 409 if the lease is staleThe server publishes { "jobId", "percent", "message", "data" } to the realtime channel job:{id}. A client that enqueued the job subscribes to that channel over /realtime/ws to watch it live.
Admin plane
POST /jobs/workers — mint a worker token
Requires the Admin role. The plaintext token is returned once (only its SHA-256 is stored).
// request
{ "name": "media-worker", "queues": ["media-gen"] } // ["*"] = any queue
// 201
{ "id": "…", "token": "wkr_…", "queues": ["media-gen"] }401 without auth; 403 for a non-admin user.
GET /jobs/workers — list tokens
Admin only. Returns metadata only — never the token or its hash.
// 200
{ "workers": [ { "id", "name", "queues": ["media-gen"], "isRevoked": false, "createdAt": "…" } ] }DELETE /jobs/workers/{id} — revoke a token
Admin only. 204 on success; 404 if the id is unknown or already revoked. A revoked token's worker-plane requests immediately become 401.
Configuration
| Env | Default | Meaning |
|---|---|---|
ATOMO_JOB_RECLAIM_INTERVAL | 30 | Seconds between sweeps that return expired leases to the queue |
See also
- Durable Jobs & External Workers — concepts + worker SDK
- Workflows API — the
Jobstep enqueues onto this queue