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

# Detections API

> List, validate, create, change, turn off, and delete detection rule packs, and run backtests over past logs.

Detection rule packs hold the Sigma and Agent Threat Rules (ATR) rules that Squasher runs on
connector logs, web server spans, and AI agent spans. Each match is a security finding. See
[Detection rules](https://docs.squasher.ai/features/detection-rules.md) for the formats and the built-in pack.

Fields use snake\_case. Write operations accept an `Idempotency-Key` header; the operations that
turn a pack off or on, delete a pack, or start a backtest require one. The same key with the same
request returns the first response; the same key with another request returns 422. Operations
that support `dry_run=true` return a preview and change nothing.

## Operations

| Operation | Method and path | Access | Purpose |
| - | - | - | - |
| `detections.list` | `GET /v1/projects/{project_id}/detections` | `findings:read` | List the packs, the built-in pack first. |
| `detections.get` | `GET /v1/projects/{project_id}/detections/{pack_id}` | `findings:read` | One pack with its rules and files. |
| `detections.validate` | `POST /v1/projects/{project_id}/detections/validate` | `findings:read` | Compile rule files. Stores nothing. |
| `detections.create` | `POST /v1/projects/{project_id}/detections` | `findings:write` | Create a custom pack. Supports `dry_run`. |
| `detections.update` | `PATCH /v1/projects/{project_id}/detections/{pack_id}` | `findings:write` | Change the name, description, or files. |
| `detections.disable` | `POST /v1/projects/{project_id}/detections/{pack_id}/disable` | `findings:write` | Turn a pack off. `detections.enable` undoes it. |
| `detections.enable` | `POST /v1/projects/{project_id}/detections/{pack_id}/enable` | `findings:write` | Turn a pack on. |
| `detections.delete` | `DELETE /v1/projects/{project_id}/detections/{pack_id}` | `findings:write` | Delete a pack. Cannot be undone. `dry_run`. |
| `detections.backtest` | `POST /v1/projects/{project_id}/detections/backtests` | `findings:write` | Start a backtest job (202). |
| `detections.backtest.get` | `GET /v1/projects/{project_id}/detections/backtests/{backtest_id}` | `findings:read` | Status, progress, and result of a job. |
| `detections.backtest.cancel` | `POST /v1/projects/{project_id}/detections/backtests/{backtest_id}/cancel` | `findings:write` | Cancel a queued or running job. |

The built-in pack has the id `builtin`. It cannot change.

## Validate rule files

```bash theme={null}
curl --request POST \
  --url "https://api.squasher.ai/v1/projects/$SQUASHER_PROJECT_ID/detections/validate" \
  --header "x-squasher-key: $SQUASHER_API_KEY" \
  --header "content-type: application/json" \
  --data '{ "rules": [{ "name": "okta_admin_token.yml", "format": "sigma", "yaml": "title: ..." }] }'
```

The response has `valid`, one entry per file (`name`, `valid`, `error`, and the compiled `rules`
with `id`, `title`, `author`, `level`, and `source`), and `error` for a problem of the whole set,
such as the same rule id in two files. Create and update return 422 with the same file entries
when a file does not compile.

## Start a backtest

Set `pack_id` (`builtin` or a custom pack id) or `rules` (draft files), and a window of at most 7
days in the past.

```bash theme={null}
curl --request POST \
  --url "https://api.squasher.ai/v1/projects/$SQUASHER_PROJECT_ID/detections/backtests" \
  --header "x-squasher-key: $SQUASHER_API_KEY" \
  --header "content-type: application/json" \
  --header "Idempotency-Key: $(uuidgen)" \
  --data '{ "pack_id": "builtin", "from": "2026-10-25T00:00:00Z", "to": "2026-11-01T00:00:00Z" }'
```

The job handle has `job_id`, `status`, `progress` (0 to 1), `error`, `created_at`, and
`updated_at`. When `status` is `succeeded`, `result` has `events_scanned`, `events_matched`,
`truncated`, and `rules` (`rule_id`, `title`, `level`, `matches`, `sample_timestamps`).

A project can have at most 2 queued or running backtests. One more start returns `429`; wait for a
job to finish, or cancel one. One compute budget covers the whole job, and a job runs for at most
240 seconds. A job that passes either limit has `status: "failed"`, an `error` that starts with
`budget_exceeded` or `time_limit_exceeded`, and the partial `result` with `truncated: true`. Use a
shorter window.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.