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

# Cleanup Jobs V1

> Tenant-managed retention. Permanently removes terminal-status jobs older than older_than_days (with their associated UsageRecord and ToolExecution rows via…

Tenant-managed retention.

Permanently removes terminal-status jobs older than `older_than_days`
(with their associated UsageRecord and ToolExecution rows via cascade).
Default mode is `dry_run=true` so callers can confirm the count
before flipping to a destructive call.

Live jobs (`queued` / `running` / `awaiting_approval`) are never
deleted, even if their status appears in the request — this is a
deliberate guardrail against trigger-and-forget tooling.

### Request body

`CleanupJobsRequest`

<ParamField body="older_than_days" type="integer" required>
  Delete jobs whose `created_at` is older than this many days. Minimum 7 days to prevent accidents — deletion is permanent and cascades to UsageRecord and ToolExecution rows.
</ParamField>

<ParamField body="statuses" type="string[]">
  Only delete jobs in one of these terminal statuses. Live jobs (queued, running, awaiting\_approval) are never touched, even if you list them here.
</ParamField>

<ParamField body="dry_run" type="boolean">
  When true (default), counts what would be deleted without deleting anything. Always start here, then re-call with `dry_run=false` once the count looks right.
</ParamField>

<ParamField body="max_delete" type="integer">
  Hard cap on rows touched in this call. Lets ops chunk large purges. Default 1000.
</ParamField>

### Response

`CleanupJobsResponse`

<ResponseField name="dry_run" type="boolean" required />

<ResponseField name="matched" type="integer" required>
  Jobs that match the criteria.
</ResponseField>

<ResponseField name="deleted" type="integer" required>
  Rows actually removed (0 when dry\_run=true).
</ResponseField>

<ResponseField name="cutoff_at" type="string" required>
  Computed `created_at` cutoff, ISO 8601.
</ResponseField>

### Status codes

| Code  | Meaning             |
| ----- | ------------------- |
| `200` | Successful Response |
| `422` | Validation Error    |

<RequestExample>
  ```bash cURL theme={null}
  curl --request POST \
    --url 'https://api.computer.stateset.app/api/v1/jobs/cleanup' \
    --header 'X-API-Key: YOUR_API_KEY' \
    --header 'Content-Type: application/json' \
    --data '{
    "older_than_days": 1,
    "statuses": [
      "string"
    ],
    "dry_run": true,
    "max_delete": 1000
  }'
  ```
</RequestExample>

<ResponseExample>
  ```json 200 theme={null}
  {
    "dry_run": false,
    "matched": 1,
    "deleted": 1,
    "cutoff_at": "2026-08-31T14:22:05Z"
  }
  ```
</ResponseExample>
