> ## Documentation Index
> Fetch the complete documentation index at: https://docs.get-exo.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Jobs

> The cross-family view of asynchronous work: imports, ingests, session backfills and brain trains.

## What this family does

Every asynchronous route in the API produces a job, and every job resolves to the same `Job` shape here. That is what makes this family the one place to watch background work, rather than three per-family status endpoints.

Jobs are keyset-paginated newest first. The `result` block on a finished job reports what the work produced: `nodesCreated`, `edgesCreated`, `domainsDetected`.

## Routes

| Method | Path                                                         | Scope   | What it does         |
| ------ | ------------------------------------------------------------ | ------- | -------------------- |
| `GET`  | [`/v1/jobs`](/api-reference/jobs/list-jobs)                  | `read`  | List jobs            |
| `GET`  | [`/v1/jobs/{job_id}`](/api-reference/jobs/get-job)           | `read`  | Get a job            |
| `POST` | [`/v1/jobs/{job_id}/cancel`](/api-reference/jobs/cancel-job) | `write` | Cancel a pending job |

## The shape of a call

Poll a job.

<CodeGroup>
  ```bash cURL theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  curl https://api.get-exo.com/v1/jobs/b1f0c6d2-8a44-4b21-9a1e-6d1f0c6d28a441a8 \
    -H "X-Exo-API-Key: $EXO_KEY"
  ```

  ```python Python theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  import httpx

  response = httpx.get(
      "https://api.get-exo.com/v1/jobs/b1f0c6d2-8a44-4b21-9a1e-6d1f0c6d28a441a8",
      headers={"X-Exo-API-Key": EXO_KEY},
  )
  job = response.json()
  ```

  ```typescript TypeScript theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  const response = await fetch("https://api.get-exo.com/v1/jobs/b1f0c6d2-8a44-4b21-9a1e-6d1f0c6d28a441a8", {
    headers: { "X-Exo-API-Key": process.env.EXO_KEY! },
  });
  const job = await response.json();
  ```
</CodeGroup>

The response:

```json theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
{
  "id": "b1f0c6d2-8a44-4b21-9a1e-6d1f0c6d28a441a8",
  "jobType": "ingest",
  "status": "succeeded",
  "createdAt": "2026-07-14T09:12:03Z",
  "completedAt": "2026-07-14T09:12:47Z",
  "error": null,
  "result": { "nodesCreated": 1, "edgesCreated": 3, "domainsDetected": 1 }
}
```

## Traps

**`done` surfaces as `succeeded`.** The internal status vocabulary is mapped to a public one. Read `succeeded`, `failed`, `canceled`, `running` and `pending`.

**Another member's job is 404, not 403.** Jobs cannot be probed. An admin key sees the whole organization; every other key sees its own jobs plus those of provisioned subjects.

**Cancel only reaches pending work.** A job the worker has claimed returns 409 `job_not_cancelable`. Cancellation never interrupts work in flight.

## Related

<Columns cols={2}>
  <Card title="API reference" icon="book-open" href="/api-reference/overview">
    Base URL, authentication, and the conventions every route shares.
  </Card>

  <Card title="Errors" icon="circle-alert" href="/platform/errors">
    The problem envelope and the full code catalogue.
  </Card>
</Columns>
