> For a complete page index of the Captain API documentation, fetch https://docs.captain.dev/llms.txt?excludeSpec=true

# Cancel Job

POST https://acme.captain.dev/v1/jobs/{job_id}/cancel

Cancel a refresh that has not started yet. 409 JOB_NOT_CANCELLABLE once it has.

Reference: https://docs.captain.dev/reference/product-search/indexes/cancel-job

## Authentication

- `Authorization` header (bearer token, required) — A write key, issued by Captain. Server side only. Sent as Authorization: Bearer \<key>.

## Request

### Path parameters

- `job_id` (string, required)

## Response

### 200

cancelled: status failed, cancelled true

- `id` (string, optional)
- `type` (enum, optional) — index.write: record updates and deletes through the ordered update log, one job per burst
  - Allowed values: `index.build`, `index.delete`, `index.import`, `index.write`
- `index` (string, optional)
- `seq_from` (integer, optional) — index.write: the first update this job carries
- `seq_to` (integer, optional) — index.write: the last update this job carries
- `records` (integer, optional) — index.write: records written
- `status` (enum, optional)
  - Allowed values: `queued`, `running`, `importing`, `succeeded`, `failed`
- `created_at` (integer, optional)
- `started_at` (integer, optional, nullable)
- `finished_at` (integer, optional, nullable)
- `stages` (list of JobStagesItems, optional)
- `progress` (BuildProgress, optional) — index.build: how far the build has got. records_done counts the records the running step has done; a step that doesn't count records (tables, verify, publish) reports every record done
- `build_id` (string, optional)
- `error` (string, optional, nullable)
- `error_code` (string, optional) — why a failed job failed; error says it in words to show. A build: BAD_VALUES (more than half of a field's values don't fit its declared type; see bad_values), BUILD_QUALITY (the build's checks refused it; the previous build keeps serving), NO_RECORDS (every record was deleted or cleared before the build read them), CANCELLED (the index is being deleted), ENGINE_ERROR (a fault on Captain's side, in the build or in running the job; the index keeps serving its previous build; retry). An index delete: DELETE_FAILED (Captain couldn't delete the index; retry). An Algolia import: the Algolia code (ALGOLIA_APP_NOT_FOUND, ALGOLIA_UNREACHABLE, ALGOLIA_INDEX_NOT_FOUND, ALGOLIA_FORBIDDEN, ALGOLIA_TIMEOUT, ALGOLIA_ERROR, INDEX_TOO_LARGE, VALIDATION_ERROR) or IMPORT_FAILED (a fault on Captain's side; nothing was changed; retry)
- `bad_values` (list of JobBadValuesItems, optional) — with error_code BAD_VALUES: per field, count of bad values, of how many, and up to 3 examples
- `warnings` (list of JobWarningsItems, optional) — \{code, message}. Settings resolved by a rule (the same warnings GET settings shows). Any build: SETTLE\_TIMEOUT (the build is live, but its search results are still settling and may shift for a few minutes; no action needed)
- `facet_report` (list of JobFacetReportItems, optional) — per number or date facet, whether it has value counts and why
- `result` (JobResult, optional, nullable)

## Types

### JobStagesItems

- `name` (enum, optional)
  - Allowed values: `schema`, `dense`, `splade`, `upload`, `tables`, `verify`, `publish`, `replicate`, `drop`, `pull`, `read`, `map`, `add`, `validate`, `embed`, `upsert`, `refresh`
- `status` (enum, optional)
  - Allowed values: `queued`, `pending`, `running`, `done`, `failed`, `skipped`
- `count` (integer, optional)
- `ms` (double, optional)
- `started_at` (double, optional)
- `finished_at` (double, optional)
- `reason` (string, optional) — why this step was skipped, in words
- `items` (integer, optional)
- `of` (integer, optional)
- `seconds` (integer, optional)

### BuildProgress

index.build: how far the build has got. records_done counts the records the running step has done; a step that doesn't count records (tables, verify, publish) reports every record done

- `step` (string, optional) — the step running now, as named in stages; queued before the first, done after the last
- `step_number` (integer, optional) — its place in the build, from 1
- `steps` (integer, optional) — steps in this build
- `records_done` (integer, optional)
- `records_total` (integer, optional, nullable)

### JobBadValuesItems

### JobWarningsItems

### JobFacetReportItems

- `field` (string, optional)
- `type` (string, optional)
- `distinct` (integer, optional, nullable)
- `facet_counts` (boolean, optional)
- `reason` (string, optional)

### JobResult

- `alias` (string, optional)
- `build` (string, optional)
- `physical` (string, optional)
- `previous` (string, optional, nullable)
- `records` (integer, optional)
- `facets` (list of string, optional)
- `seconds` (integer, optional)
- `checks` (JobResultChecks, optional)
- `constraints` (JobResultConstraints, optional) — index.build: whether measurement queries ('under 30 inches') are scored on the new build, and why not
- `report` (string, optional) — index.import: where the import report is
- `build_job` (string, optional, nullable) — index.import: the build job it queued

### JobResultChecks

### JobResultConstraints

index.build: whether measurement queries ('under 30 inches') are scored on the new build, and why not

- `ranking` (boolean, required)
- `reason` (string, required, nullable)

## Examples

**Response**

```json
{
  "id": "job_20261002193012_9f8e7d",
  "type": "index.build",
  "index": "products",
  "status": "failed",
  "created_at": 1759433412,
  "started_at": null,
  "finished_at": 1759433415,
  "error": "cancelled by key key_2c7e90a1b4d35f18 before it started",
  "cancelled": true
}
```

**SDK Code**

```python Python REST
import json
import requests

BASE_URL = "https://acme.captain.dev"
API_KEY = "your_write_key"
JOB_ID = "job_20261002193012_9f8e7d"

headers = {
    "Authorization": f"Bearer {API_KEY}",
}

response = requests.post(
    f"{BASE_URL}/v1/jobs/{JOB_ID}/cancel",
    headers=headers,
    timeout=30.0,
)

print(json.dumps(response.json(), indent=2))
```

```typescript TypeScript REST
const BASE_URL = "https://acme.captain.dev";
const API_KEY = "your_write_key";
const jobId = "job_20261002193012_9f8e7d";

const response = await fetch(`${BASE_URL}/v1/jobs/${jobId}/cancel`, {
  method: "POST",
  headers: {
    Authorization: `Bearer ${API_KEY}`,
  },
});

const result = await response.json();
console.log(JSON.stringify(result, null, 2));
```