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

# Jobs

Following it, collecting it, stopping it.

## List jobs, newest first

> How a lost id is recovered. Does not poll the upstream services: statuses are as fresh as the last settle, and GET /jobs/{id} is what reconciles one.

```json
{"openapi":"3.1.0","info":{"title":"Auray API","version":"1.0.0"},"tags":[{"name":"Jobs","description":"Following it, collecting it, stopping it."}],"servers":[{"url":"https://api.auray.ai/v1"}],"security":[{"apiKey":[]}],"components":{"securitySchemes":{"apiKey":{"type":"http","scheme":"bearer","bearerFormat":"auray_sk_","description":"Create one in Settings -> API Keys. Seventy-one characters: auray_sk_, a public twelve-character id, an underscore, and a secret we store only as a one-way hash. Every key expires; the maximum life is 366 days."}},"schemas":{"Product":{"type":"string","enum":["photo","music","video","threed","chat"]},"Status":{"type":"string","enum":["queued","running","succeeded","failed","cancelled"],"description":"Five words, whatever the product. Our internals disagree; you never see that."},"Error":{"type":"object","required":["error","message","request_id"],"properties":{"error":{"type":"string","description":"For your code."},"message":{"type":"string","description":"A sentence, for a human reading a log."},"docs":{"type":"string"},"request_id":{"type":"string","description":"Quote this if you write in."}}}},"responses":{"Error":{"description":"Refused. See `error` for the machine-readable code.","headers":{"X-Request-Id":{"schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/jobs":{"get":{"summary":"List jobs, newest first","description":"How a lost id is recovered. Does not poll the upstream services: statuses are as fresh as the last settle, and GET /jobs/{id} is what reconciles one.","operationId":"listJobs","tags":["Jobs"],"parameters":[{"name":"product","in":"query","schema":{"$ref":"#/components/schemas/Product"}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}},{"name":"settled","in":"query","schema":{"type":"string","enum":["true","false"]}},{"name":"before","in":"query","schema":{"type":"string","format":"date-time"},"description":"Cursor. Feed back the next_before from the previous page."}],"responses":{"200":{"description":"OK","headers":{"RateLimit-Limit":{"schema":{"type":"integer"},"description":"Burst capacity."},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"},"description":"Seconds until refill."},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix seconds. The X- spelling is what client libraries read."},"X-Request-Id":{"schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","enum":["list"]},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"object":{"type":"string","enum":["job"]},"product":{"$ref":"#/components/schemas/Product"},"status":{"$ref":"#/components/schemas/Status"},"credits_charged":{"type":"integer"},"settled":{"type":"boolean"},"origin":{"type":"string","enum":["ui","api"],"description":"Which door the job came in by. NOT the same vocabulary as `/usage`, which says `app` rather than `ui` for the same idea — the jobs tables and the credit ledger were given different words and both are load-bearing. Chat turns always read `ui`: `chat_messages` has no origin column."},"created_at":{"type":"string","format":"date-time","description":"When it was submitted. This is the field the list is ordered by, and the value to feed back as `?before=`."}}}},"next_before":{"type":["string","null"],"format":"date-time","description":"Present only when there is another page."},"request_id":{"type":"string","description":"Mirrored in the X-Request-Id header. It sits here, on the envelope, not on each item."}}}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"},"503":{"$ref":"#/components/responses/Error"}}}}}}
```

## How is my job doing

> Read one job, reconciling it first where that is possible. Photo, music and 3D are polled against their own service, so this is the call that turns a stale row into a settled one. VIDEO AND CHAT ARE NOT POLLED and deliberately so — video settles from its callback and chat from the turn itself, so for those two this reports what is already stored. \`poll\_after\_seconds\` is present only while the job is unsettled, so a loop can stop on its absence rather than on a status it has to interpret.

```json
{"openapi":"3.1.0","info":{"title":"Auray API","version":"1.0.0"},"tags":[{"name":"Jobs","description":"Following it, collecting it, stopping it."}],"servers":[{"url":"https://api.auray.ai/v1"}],"security":[{"apiKey":[]}],"components":{"securitySchemes":{"apiKey":{"type":"http","scheme":"bearer","bearerFormat":"auray_sk_","description":"Create one in Settings -> API Keys. Seventy-one characters: auray_sk_, a public twelve-character id, an underscore, and a secret we store only as a one-way hash. Every key expires; the maximum life is 366 days."}},"schemas":{"Product":{"type":"string","enum":["photo","music","video","threed","chat"]},"Status":{"type":"string","enum":["queued","running","succeeded","failed","cancelled"],"description":"Five words, whatever the product. Our internals disagree; you never see that."},"AssetDescriptor":{"type":"object","description":"Describes an asset. Never a URL — get those from /jobs/{id}/assets.","properties":{"index":{"type":"integer"},"kind":{"type":"string","enum":["image","audio","video","model"]},"key":{"type":["string","null"]},"bytes":{"type":["integer","null"]},"width":{"type":["integer","null"]},"height":{"type":["integer","null"]},"stage":{"type":"string","description":"3D only."},"seconds":{"type":["number","null"],"description":"Audio and video assets: the real duration, once known."},"sample_rate":{"type":["integer","null"],"description":"Audio assets only."},"channels":{"type":["integer","null"],"description":"Audio assets only."}}},"Error":{"type":"object","required":["error","message","request_id"],"properties":{"error":{"type":"string","description":"For your code."},"message":{"type":"string","description":"A sentence, for a human reading a log."},"docs":{"type":"string"},"request_id":{"type":"string","description":"Quote this if you write in."}}}},"responses":{"Error":{"description":"Refused. See `error` for the machine-readable code.","headers":{"X-Request-Id":{"schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/jobs/{id}":{"get":{"summary":"How is my job doing","description":"Read one job, reconciling it first where that is possible. Photo, music and 3D are polled against their own service, so this is the call that turns a stale row into a settled one. VIDEO AND CHAT ARE NOT POLLED and deliberately so — video settles from its callback and chat from the turn itself, so for those two this reports what is already stored. `poll_after_seconds` is present only while the job is unsettled, so a loop can stop on its absence rather than on a status it has to interpret.","operationId":"getJob","tags":["Jobs"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"include_reasoning","in":"query","schema":{"type":"string","enum":["true"]},"description":"Chat only. Reasoning often runs several times the length of the answer."}],"responses":{"200":{"description":"OK","headers":{"RateLimit-Limit":{"schema":{"type":"integer"},"description":"Burst capacity."},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"},"description":"Seconds until refill."},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix seconds. The X- spelling is what client libraries read."},"X-Request-Id":{"schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"object":{"type":"string","enum":["job"]},"product":{"$ref":"#/components/schemas/Product"},"status":{"$ref":"#/components/schemas/Status"},"provider_job_id":{"type":["string","null"]},"credits_charged":{"type":"integer"},"settled":{"type":"boolean"},"poll_after_seconds":{"type":"integer"},"assets":{"type":"array","items":{"$ref":"#/components/schemas/AssetDescriptor"}},"request_id":{"type":"string"},"conversation_id":{"type":"string","description":"The thread this turn belongs to. Chat jobs only; absent on every other product."},"model":{"type":["string","null"],"description":"The model that answered. Chat jobs only; absent on every other product. Null until the model is known."},"credits_reserved":{"type":"integer","description":"What was held against the worst case before the model ran. Chat jobs only; absent on every other product."},"content":{"type":"string","description":"The answer text. Chat jobs only; absent on every other product."},"finish_reason":{"type":["string","null"],"description":"Why generation stopped. Chat jobs only; absent on every other product. Null until the turn settles, and on a turn that stopped before reporting."},"usage":{"type":"object","description":"Token counts for the turn. Chat jobs only; absent on every other product. Every count is null until the turn settles — and stays null on a turn that was stopped or failed, because the usage frame routinely never arrives.","properties":{"prompt_tokens":{"type":["integer","null"]},"cached_prompt_tokens":{"type":["integer","null"]},"completion_tokens":{"type":["integer","null"]},"reasoning_tokens":{"type":["integer","null"]}}},"reasoning":{"type":"string","description":"The model's reasoning, present only when `include_reasoning=true` was asked for. Often several times the length of the answer. Chat jobs only; absent on every other product."},"created_at":{"type":"string","format":"date-time","description":"When the job was submitted."},"error":{"type":["string","null"],"description":"Why it failed, in the upstream's words. Null unless it did."},"error_code":{"type":["string","null"],"description":"A stable code for the same failure, where the service gives one."},"refused":{"type":"integer","minimum":0,"description":"How many images the safety filter withheld. Photo only; absent on every other product."},"upstream_lost":{"type":"boolean","enum":[true],"description":"Present, and only ever true, when the rendering service no longer has any record of this job. It keeps them for a few days, so an old id reads the same as one that never existed. Absent otherwise."}}}}}},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"},"503":{"$ref":"#/components/responses/Error"}}}}}}
```

## Stop a job that is still running

> Settles what it was worth; does not delete the row. Photo refunds in full, music and video bill the fraction burned, 3D keeps the completed stages' shares. Cancelling something already finished is 200 with cancelled:false, not an error. 3D can answer 409 cancel\_refused when its service will not stop the container.

```json
{"openapi":"3.1.0","info":{"title":"Auray API","version":"1.0.0"},"tags":[{"name":"Jobs","description":"Following it, collecting it, stopping it."}],"servers":[{"url":"https://api.auray.ai/v1"}],"security":[{"apiKey":[]}],"components":{"securitySchemes":{"apiKey":{"type":"http","scheme":"bearer","bearerFormat":"auray_sk_","description":"Create one in Settings -> API Keys. Seventy-one characters: auray_sk_, a public twelve-character id, an underscore, and a secret we store only as a one-way hash. Every key expires; the maximum life is 366 days."}},"schemas":{"Status":{"type":"string","enum":["queued","running","succeeded","failed","cancelled"],"description":"Five words, whatever the product. Our internals disagree; you never see that."},"Error":{"type":"object","required":["error","message","request_id"],"properties":{"error":{"type":"string","description":"For your code."},"message":{"type":"string","description":"A sentence, for a human reading a log."},"docs":{"type":"string"},"request_id":{"type":"string","description":"Quote this if you write in."}}}},"responses":{"Error":{"description":"Refused. See `error` for the machine-readable code.","headers":{"X-Request-Id":{"schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/jobs/{id}":{"delete":{"summary":"Stop a job that is still running","description":"Settles what it was worth; does not delete the row. Photo refunds in full, music and video bill the fraction burned, 3D keeps the completed stages' shares. Cancelling something already finished is 200 with cancelled:false, not an error. 3D can answer 409 cancel_refused when its service will not stop the container.","operationId":"cancelJob","tags":["Jobs"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","headers":{"RateLimit-Limit":{"schema":{"type":"integer"},"description":"Burst capacity."},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"},"description":"Seconds until refill."},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix seconds. The X- spelling is what client libraries read."},"X-Request-Id":{"schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"status":{"$ref":"#/components/schemas/Status"},"cancelled":{"type":"boolean"},"settled":{"type":"boolean"},"credits_charged":{"type":"integer"}}}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"409":{"$ref":"#/components/responses/Error"},"410":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"},"500":{"description":"`settle_failed` — the cancel reached the service, but the outcome could not be recorded. Read the job again in a moment.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"$ref":"#/components/responses/Error"},"503":{"$ref":"#/components/responses/Error"}}}}}}
```

## Signed URLs for what a job produced

> Signs and does not proxy: fetch the URLs directly. They live fifteen minutes, which is what makes soft delete real. Spends the egress bucket in whole megabytes.

```json
{"openapi":"3.1.0","info":{"title":"Auray API","version":"1.0.0"},"tags":[{"name":"Jobs","description":"Following it, collecting it, stopping it."}],"servers":[{"url":"https://api.auray.ai/v1"}],"security":[{"apiKey":[]}],"components":{"securitySchemes":{"apiKey":{"type":"http","scheme":"bearer","bearerFormat":"auray_sk_","description":"Create one in Settings -> API Keys. Seventy-one characters: auray_sk_, a public twelve-character id, an underscore, and a secret we store only as a one-way hash. Every key expires; the maximum life is 366 days."}},"schemas":{"Product":{"type":"string","enum":["photo","music","video","threed","chat"]},"Error":{"type":"object","required":["error","message","request_id"],"properties":{"error":{"type":"string","description":"For your code."},"message":{"type":"string","description":"A sentence, for a human reading a log."},"docs":{"type":"string"},"request_id":{"type":"string","description":"Quote this if you write in."}}}},"responses":{"Error":{"description":"Refused. See `error` for the machine-readable code.","headers":{"X-Request-Id":{"schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/jobs/{id}/assets":{"get":{"summary":"Signed URLs for what a job produced","description":"Signs and does not proxy: fetch the URLs directly. They live fifteen minutes, which is what makes soft delete real. Spends the egress bucket in whole megabytes.","operationId":"getJobAssets","tags":["Jobs"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","headers":{"RateLimit-Limit":{"schema":{"type":"integer"},"description":"Burst capacity."},"RateLimit-Remaining":{"schema":{"type":"integer"}},"RateLimit-Reset":{"schema":{"type":"integer"},"description":"Seconds until refill."},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix seconds. The X- spelling is what client libraries read."},"X-Request-Id":{"schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"object":{"type":"string","enum":["asset_list"]},"product":{"$ref":"#/components/schemas/Product"},"expires_at":{"type":["string","null"],"format":"date-time"},"megabytes_charged":{"type":"integer"},"assets":{"type":"array","items":{"type":"object","properties":{"index":{"type":"integer"},"kind":{"type":"string"},"filename":{"type":"string"},"content_type":{"type":"string"},"bytes":{"type":["integer","null"]},"url":{"type":"string","format":"uri"}}}}}}}}},"401":{"$ref":"#/components/responses/Error"},"402":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"409":{"$ref":"#/components/responses/Error"},"410":{"$ref":"#/components/responses/Error"},"413":{"description":"`request_too_large` — the signed URLs would cost more of the `egress` bucket than the bucket can ever hold. Ask for a smaller job, or a larger plan.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/Error"},"503":{"$ref":"#/components/responses/Error"}}}}}}
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.auray.ai/api-reference/jobs.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
