> For the complete documentation index, see [llms.txt](https://docs.projectsim.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.projectsim.ai/api-reference/jobs.md).

# Jobs

## List Jobs

> List your jobs, newest first.\
> \
> Cursor-paginated. Filter by \`status\`, and by \`resource\_type\` —\
> \`asset\`, \`variation\_set\` or \`scene\`.

```json
{"openapi":"3.1.0","info":{"title":"projectsim API","version":"1.0.0-beta"},"security":[{"ProjectSimToken":[]}],"components":{"securitySchemes":{"ProjectSimToken":{"bearerFormat":"kps_live_...","description":"A per-user API token. The tenant is the user, so no request body carries a user id. Tokens without the `kps_` prefix are rejected before any lookup.","scheme":"bearer","type":"http"}},"schemas":{"JobListResponse":{"properties":{"jobs":{"items":{"$ref":"#/components/schemas/JobResponse"},"title":"Jobs","type":"array"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Null on the last page.","title":"Next Cursor"}},"required":["jobs"],"title":"JobListResponse","type":"object"},"JobResponse":{"description":"One execution against a resource — the public status surface.","properties":{"created_at":{"format":"date-time","title":"Created At","type":"string"},"current_stage":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"While running: variation · reconstruction · scale · physics","title":"Current Stage"},"error":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"description":"An RFC 7807 problem object when the job failed.","title":"Error"},"id":{"title":"Id","type":"string"},"progress":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Progress"},"resource":{"$ref":"#/components/schemas/ResourceRef"},"status":{"description":"queued · running · complete · failed · canceled · partial (variation sets and batches)","title":"Status","type":"string"},"updated_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"title":"Updated At"}},"required":["id","resource","status","created_at"],"title":"JobResponse","type":"object"},"ResourceRef":{"description":"What a job or delivery is about.","properties":{"id":{"title":"Id","type":"string"},"type":{"description":"asset · variation_set · scene · batch","title":"Type","type":"string"}},"required":["type","id"],"title":"ResourceRef","type":"object"},"Problem":{"description":"An RFC 7807 error, the shape every failure uses.\n\nDeclared explicitly because the handlers replace FastAPI's default\nvalidation response; without this the spec would advertise\n`HTTPValidationError`, whose `detail` is a list rather than a string,\nand every generated client would crash parsing a 422.","properties":{"detail":{"description":"Human-readable explanation of this occurrence.","title":"Detail","type":"string"},"errors":{"anyOf":[{"items":{"$ref":"#/components/schemas/ValidationDetail"},"type":"array"},{"type":"null"}],"description":"Present on a 422; one entry per failing field.","title":"Errors"},"instance":{"description":"Identifies this occurrence; quote it to support.","title":"Instance","type":"string"},"path":{"title":"Path","type":"string"},"request_id":{"description":"Also returned in the X-Request-Id response header.","title":"Request Id","type":"string"},"status":{"title":"Status","type":"integer"},"title":{"title":"Title","type":"string"},"type":{"description":"Stable URI identifying the error class.","title":"Type","type":"string"}},"required":["type","title","status","detail","instance","path","request_id"],"title":"Problem","type":"object"},"ValidationDetail":{"description":"One field-level validation failure.","properties":{"loc":{"description":"Dotted path to the offending field.","title":"Loc","type":"string"},"msg":{"title":"Msg","type":"string"},"type":{"title":"Type","type":"string"}},"required":["loc","msg","type"],"title":"ValidationDetail","type":"object"}}},"paths":{"/v1/jobs":{"get":{"description":"List your jobs, newest first.\n\nCursor-paginated. Filter by `status`, and by `resource_type` —\n`asset`, `variation_set` or `scene`.","operationId":"list_jobs","parameters":[{"in":"query","name":"status","required":false,"schema":{"anyOf":[{"enum":["queued","running","complete","failed","canceled","partial"],"type":"string"},{"type":"null"}],"title":"Status"}},{"in":"query","name":"resource_type","required":false,"schema":{"anyOf":[{"enum":["asset","variation_set","scene","batch"],"type":"string"},{"type":"null"}],"title":"Resource Type"}},{"in":"query","name":"limit","required":false,"schema":{"default":50,"maximum":100,"minimum":1,"title":"Limit","type":"integer"}},{"in":"query","name":"cursor","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cursor"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobListResponse"}}},"description":"Successful Response"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Missing or invalid API token"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Request body too large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Request failed validation"}},"summary":"List Jobs","tags":["jobs"]}}}}
```

## Bulk Statuses

> Look up many jobs in one call.\
> \
> Takes up to 100 job IDs and returns a map keyed by the IDs you\
> sent. An ID that does not exist, or that you do not own, comes\
> back as null rather than failing the whole request.\
> \
> Prefer this over one request per job when tracking a large batch.

```json
{"openapi":"3.1.0","info":{"title":"projectsim API","version":"1.0.0-beta"},"security":[{"ProjectSimToken":[]}],"components":{"securitySchemes":{"ProjectSimToken":{"bearerFormat":"kps_live_...","description":"A per-user API token. The tenant is the user, so no request body carries a user id. Tokens without the `kps_` prefix are rejected before any lookup.","scheme":"bearer","type":"http"}},"schemas":{"BulkStatusRequest":{"additionalProperties":false,"properties":{"ids":{"items":{"type":"string"},"maxItems":100,"minItems":1,"title":"Ids","type":"array"}},"required":["ids"],"title":"BulkStatusRequest","type":"object"},"BulkStatusResponse":{"properties":{"jobs":{"additionalProperties":{"anyOf":[{"$ref":"#/components/schemas/JobResponse"},{"type":"null"}]},"description":"Keyed by the ids you sent. An id that does not exist, or that you do not own, is null.","title":"Jobs","type":"object"}},"required":["jobs"],"title":"BulkStatusResponse","type":"object"},"JobResponse":{"description":"One execution against a resource — the public status surface.","properties":{"created_at":{"format":"date-time","title":"Created At","type":"string"},"current_stage":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"While running: variation · reconstruction · scale · physics","title":"Current Stage"},"error":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"description":"An RFC 7807 problem object when the job failed.","title":"Error"},"id":{"title":"Id","type":"string"},"progress":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Progress"},"resource":{"$ref":"#/components/schemas/ResourceRef"},"status":{"description":"queued · running · complete · failed · canceled · partial (variation sets and batches)","title":"Status","type":"string"},"updated_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"title":"Updated At"}},"required":["id","resource","status","created_at"],"title":"JobResponse","type":"object"},"ResourceRef":{"description":"What a job or delivery is about.","properties":{"id":{"title":"Id","type":"string"},"type":{"description":"asset · variation_set · scene · batch","title":"Type","type":"string"}},"required":["type","id"],"title":"ResourceRef","type":"object"},"Problem":{"description":"An RFC 7807 error, the shape every failure uses.\n\nDeclared explicitly because the handlers replace FastAPI's default\nvalidation response; without this the spec would advertise\n`HTTPValidationError`, whose `detail` is a list rather than a string,\nand every generated client would crash parsing a 422.","properties":{"detail":{"description":"Human-readable explanation of this occurrence.","title":"Detail","type":"string"},"errors":{"anyOf":[{"items":{"$ref":"#/components/schemas/ValidationDetail"},"type":"array"},{"type":"null"}],"description":"Present on a 422; one entry per failing field.","title":"Errors"},"instance":{"description":"Identifies this occurrence; quote it to support.","title":"Instance","type":"string"},"path":{"title":"Path","type":"string"},"request_id":{"description":"Also returned in the X-Request-Id response header.","title":"Request Id","type":"string"},"status":{"title":"Status","type":"integer"},"title":{"title":"Title","type":"string"},"type":{"description":"Stable URI identifying the error class.","title":"Type","type":"string"}},"required":["type","title","status","detail","instance","path","request_id"],"title":"Problem","type":"object"},"ValidationDetail":{"description":"One field-level validation failure.","properties":{"loc":{"description":"Dotted path to the offending field.","title":"Loc","type":"string"},"msg":{"title":"Msg","type":"string"},"type":{"title":"Type","type":"string"}},"required":["loc","msg","type"],"title":"ValidationDetail","type":"object"}}},"paths":{"/v1/jobs/statuses":{"post":{"description":"Look up many jobs in one call.\n\nTakes up to 100 job IDs and returns a map keyed by the IDs you\nsent. An ID that does not exist, or that you do not own, comes\nback as null rather than failing the whole request.\n\nPrefer this over one request per job when tracking a large batch.","operationId":"bulk_statuses","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkStatusRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkStatusResponse"}}},"description":"Successful Response"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Missing or invalid API token"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Request body too large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Request failed validation"}},"summary":"Bulk Statuses","tags":["jobs"]}}}}
```

## Get Job

> Retrieve one job — the single polling surface for every resource.\
> \
> \`status\` moves \`queued\` → \`running\` → \`complete\`, or to \`failed\`.\
> \`canceled\` and \`partial\` are terminal too, and \`partial\` applies to\
> variation sets only.\
> \
> While running, \`current\_stage\` is one of \`variation\`,\
> \`reconstruction\`, \`scale\` or \`physics\`.\
> \
> A poll loop is guaranteed to terminate: the time budget is\
> measured from creation with queue time included, and an expired\
> job moves to \`failed\`.\
> \
> A job id names one execution and always resolves to that run, so it\
> never goes stale — but a resource can have more than one job over\
> time, and a later one will not appear here. The asset is the durable\
> handle: \`GET /v1/assets/{asset\_id}\` always reports its current job.\
> Poll the job for the run you started, the asset for where the asset\
> has got to.

```json
{"openapi":"3.1.0","info":{"title":"projectsim API","version":"1.0.0-beta"},"security":[{"ProjectSimToken":[]}],"components":{"securitySchemes":{"ProjectSimToken":{"bearerFormat":"kps_live_...","description":"A per-user API token. The tenant is the user, so no request body carries a user id. Tokens without the `kps_` prefix are rejected before any lookup.","scheme":"bearer","type":"http"}},"schemas":{"JobResponse":{"description":"One execution against a resource — the public status surface.","properties":{"created_at":{"format":"date-time","title":"Created At","type":"string"},"current_stage":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"While running: variation · reconstruction · scale · physics","title":"Current Stage"},"error":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"description":"An RFC 7807 problem object when the job failed.","title":"Error"},"id":{"title":"Id","type":"string"},"progress":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Progress"},"resource":{"$ref":"#/components/schemas/ResourceRef"},"status":{"description":"queued · running · complete · failed · canceled · partial (variation sets and batches)","title":"Status","type":"string"},"updated_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"title":"Updated At"}},"required":["id","resource","status","created_at"],"title":"JobResponse","type":"object"},"ResourceRef":{"description":"What a job or delivery is about.","properties":{"id":{"title":"Id","type":"string"},"type":{"description":"asset · variation_set · scene · batch","title":"Type","type":"string"}},"required":["type","id"],"title":"ResourceRef","type":"object"},"Problem":{"description":"An RFC 7807 error, the shape every failure uses.\n\nDeclared explicitly because the handlers replace FastAPI's default\nvalidation response; without this the spec would advertise\n`HTTPValidationError`, whose `detail` is a list rather than a string,\nand every generated client would crash parsing a 422.","properties":{"detail":{"description":"Human-readable explanation of this occurrence.","title":"Detail","type":"string"},"errors":{"anyOf":[{"items":{"$ref":"#/components/schemas/ValidationDetail"},"type":"array"},{"type":"null"}],"description":"Present on a 422; one entry per failing field.","title":"Errors"},"instance":{"description":"Identifies this occurrence; quote it to support.","title":"Instance","type":"string"},"path":{"title":"Path","type":"string"},"request_id":{"description":"Also returned in the X-Request-Id response header.","title":"Request Id","type":"string"},"status":{"title":"Status","type":"integer"},"title":{"title":"Title","type":"string"},"type":{"description":"Stable URI identifying the error class.","title":"Type","type":"string"}},"required":["type","title","status","detail","instance","path","request_id"],"title":"Problem","type":"object"},"ValidationDetail":{"description":"One field-level validation failure.","properties":{"loc":{"description":"Dotted path to the offending field.","title":"Loc","type":"string"},"msg":{"title":"Msg","type":"string"},"type":{"title":"Type","type":"string"}},"required":["loc","msg","type"],"title":"ValidationDetail","type":"object"}}},"paths":{"/v1/jobs/{job_id}":{"get":{"description":"Retrieve one job — the single polling surface for every resource.\n\n`status` moves `queued` → `running` → `complete`, or to `failed`.\n`canceled` and `partial` are terminal too, and `partial` applies to\nvariation sets only.\n\nWhile running, `current_stage` is one of `variation`,\n`reconstruction`, `scale` or `physics`.\n\nA poll loop is guaranteed to terminate: the time budget is\nmeasured from creation with queue time included, and an expired\njob moves to `failed`.\n\nA job id names one execution and always resolves to that run, so it\nnever goes stale — but a resource can have more than one job over\ntime, and a later one will not appear here. The asset is the durable\nhandle: `GET /v1/assets/{asset_id}` always reports its current job.\nPoll the job for the run you started, the asset for where the asset\nhas got to.","operationId":"get_job","parameters":[{"in":"path","name":"job_id","required":true,"schema":{"title":"Job Id","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobResponse"}}},"description":"Successful Response"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Missing or invalid API token"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Request body too large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Request failed validation"}},"summary":"Get Job","tags":["jobs"]}}}}
```

## Cancel Job

> Cancel a job before it starts generating.\
> \
> Returns \`200\` with the job, now \`canceled\`, and fires \`asset.canceled\`\
> or \`variation\_set.canceled\`. Nothing is generated for it, and its asset\
> no longer counts toward any asset limit. Canceling a variation set's\
> job cancels its members with it, until any member has started.\
> \
> Idempotent — canceling a \`canceled\` job returns it unchanged. Returns\
> \`409\` once generation has started (\`job-started\`), for a job that\
> already finished (\`job-finished\`), and for a variation set member's own\
> job (\`variation-set-member\`): cancel the set instead.

```json
{"openapi":"3.1.0","info":{"title":"projectsim API","version":"1.0.0-beta"},"security":[{"ProjectSimToken":[]}],"components":{"securitySchemes":{"ProjectSimToken":{"bearerFormat":"kps_live_...","description":"A per-user API token. The tenant is the user, so no request body carries a user id. Tokens without the `kps_` prefix are rejected before any lookup.","scheme":"bearer","type":"http"}},"schemas":{"JobResponse":{"description":"One execution against a resource — the public status surface.","properties":{"created_at":{"format":"date-time","title":"Created At","type":"string"},"current_stage":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"While running: variation · reconstruction · scale · physics","title":"Current Stage"},"error":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"description":"An RFC 7807 problem object when the job failed.","title":"Error"},"id":{"title":"Id","type":"string"},"progress":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Progress"},"resource":{"$ref":"#/components/schemas/ResourceRef"},"status":{"description":"queued · running · complete · failed · canceled · partial (variation sets and batches)","title":"Status","type":"string"},"updated_at":{"anyOf":[{"format":"date-time","type":"string"},{"type":"null"}],"title":"Updated At"}},"required":["id","resource","status","created_at"],"title":"JobResponse","type":"object"},"ResourceRef":{"description":"What a job or delivery is about.","properties":{"id":{"title":"Id","type":"string"},"type":{"description":"asset · variation_set · scene · batch","title":"Type","type":"string"}},"required":["type","id"],"title":"ResourceRef","type":"object"},"Problem":{"description":"An RFC 7807 error, the shape every failure uses.\n\nDeclared explicitly because the handlers replace FastAPI's default\nvalidation response; without this the spec would advertise\n`HTTPValidationError`, whose `detail` is a list rather than a string,\nand every generated client would crash parsing a 422.","properties":{"detail":{"description":"Human-readable explanation of this occurrence.","title":"Detail","type":"string"},"errors":{"anyOf":[{"items":{"$ref":"#/components/schemas/ValidationDetail"},"type":"array"},{"type":"null"}],"description":"Present on a 422; one entry per failing field.","title":"Errors"},"instance":{"description":"Identifies this occurrence; quote it to support.","title":"Instance","type":"string"},"path":{"title":"Path","type":"string"},"request_id":{"description":"Also returned in the X-Request-Id response header.","title":"Request Id","type":"string"},"status":{"title":"Status","type":"integer"},"title":{"title":"Title","type":"string"},"type":{"description":"Stable URI identifying the error class.","title":"Type","type":"string"}},"required":["type","title","status","detail","instance","path","request_id"],"title":"Problem","type":"object"},"ValidationDetail":{"description":"One field-level validation failure.","properties":{"loc":{"description":"Dotted path to the offending field.","title":"Loc","type":"string"},"msg":{"title":"Msg","type":"string"},"type":{"title":"Type","type":"string"}},"required":["loc","msg","type"],"title":"ValidationDetail","type":"object"}}},"paths":{"/v1/jobs/{job_id}/cancel":{"post":{"description":"Cancel a job before it starts generating.\n\nReturns `200` with the job, now `canceled`, and fires `asset.canceled`\nor `variation_set.canceled`. Nothing is generated for it, and its asset\nno longer counts toward any asset limit. Canceling a variation set's\njob cancels its members with it, until any member has started.\n\nIdempotent — canceling a `canceled` job returns it unchanged. Returns\n`409` once generation has started (`job-started`), for a job that\nalready finished (`job-finished`), and for a variation set member's own\njob (`variation-set-member`): cancel the set instead.","operationId":"cancel_job","parameters":[{"in":"path","name":"job_id","required":true,"schema":{"title":"Job Id","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobResponse"}}},"description":"Successful Response"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Missing or invalid API token"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The job does not exist"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The job cannot be canceled"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Request body too large"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Request failed validation"}},"summary":"Cancel Job","tags":["jobs"]}}}}
```
