> ## 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.

# Investigations API

> Start, read, steer, and cancel investigations, and approve or reject the actions that they propose.

An [investigation](/features/investigations) is a case that Squasher works on: a question, a
status, a suspected cause, a confidence, and a timeline. While Squasher investigates, it can propose
an action, such as a fix pull request. A person approves or rejects each action.

## Operations

| Operation | Method and path | Access | Purpose |
| - | - | - | - |
| `investigations.list` | `GET /v1/projects/{project_id}/investigations` | `investigations:read` | List investigations. |
| `investigations.create` | `POST /v1/projects/{project_id}/investigations` | `investigations:write` | Start an investigation. |
| `investigations.get` | `GET /v1/projects/{project_id}/investigations/{investigation_id}` | `investigations:read` | Read one investigation, its timeline, actions. |
| `investigations.addNote` | `POST /v1/projects/{project_id}/investigations/{investigation_id}/notes` | `investigations:write` | Add a note to the timeline. |
| `investigations.redirect` | `POST /v1/projects/{project_id}/investigations/{investigation_id}/redirect` | `investigations:write` | Steer the investigation in a new direction. |
| `investigations.cancel` | `POST /v1/projects/{project_id}/investigations/{investigation_id}/cancel` | `investigations:write` | Stop an active investigation. |
| `actions.list` | `GET /v1/projects/{project_id}/actions` | `investigations:read` | List proposed and finished actions. |
| `actions.approve` | `POST /v1/projects/{project_id}/actions/{action_id}/approve` | `actions:approve` | Approve an action and run it at once. |
| `actions.reject` | `POST /v1/projects/{project_id}/actions/{action_id}/reject` | `actions:approve` | Reject an action. |
| `actions.resolve` | `POST /v1/projects/{project_id}/actions/{action_id}/resolve` | `actions:approve` | Settle an action whose result is unknown. |

Project members can start, steer, and cancel investigations. Only an owner or admin can approve,
reject, or resolve an action, and only with a signed-in user token: the dashboard, or the CLI after
`squasher login`. The API refuses API keys for these three operations, even a key with the
`actions:approve` scope. The decision records your user id.

## Start an investigation

The body has a question, a subject, or both:

| Field | Description |
| - | - |
| `question` | The question to answer. At most 4,000 characters. |
| `subject` | What to investigate: `{ "kind", "id", "label" }`. `kind` is `incident`, `issue`, `finding`, `monitor`, `release`, `service`, `entity`, `trace`, or `agent_session`. |
| `idempotency_key` | Optional. A repeated request with the same key returns the same investigation. |

```bash theme={null}
curl --request POST \
  --url "https://api.squasher.ai/v1/projects/$SQUASHER_PROJECT_ID/investigations" \
  --header "x-squasher-key: $SQUASHER_API_KEY" \
  --header "content-type: application/json" \
  --data '{ "question": "Why did checkout errors increase after 10:00?" }'
```

The response has status `201`, `created: true`, and the new investigation. An incident has one
investigation. When the subject is an incident that already has one, the response has status `200`,
`created: false`, and the existing investigation. A repeated `idempotency_key` also returns `200`.

```json theme={null}
{
  "created": true,
  "investigation": {
    "id": "3f1c2b7a-8d4e-4a9b-b6c1-2e5f0a7d9c13",
    "status": "queued",
    "question": "Why did checkout errors increase after 10:00?",
    "summary": null,
    "suspected_cause": null,
    "confidence": null,
    "severity": null,
    "next_steps": [],
    "trigger": { "kind": "question", "id": null },
    "subjects": [],
    "incident_id": null,
    "issue_id": null,
    "thread_id": "c7a9e2d4-1b3f-4c8a-9e6d-5f2b0a1c7e38",
    "created_at": "2026-10-11T10:04:00.000Z",
    "diagnosed_at": null,
    "time_to_diagnosis_seconds": null
  }
}
```

The example leaves out some fields. `confidence` is a number from 0 to 100.
`time_to_diagnosis_seconds` is the time from the start to the first diagnosis. `thread_id` is the
chat that is linked to the investigation.

## List investigations

```bash theme={null}
curl --url "https://api.squasher.ai/v1/projects/$SQUASHER_PROJECT_ID/investigations?view=active" \
  --header "x-squasher-key: $SQUASHER_API_KEY"
```

| Parameter | Description |
| - | - |
| `view` | `active` (queued and investigating), `history` (finished), or `all`. Default `all`. |
| `status` | `queued`, `investigating`, `diagnosed`, `inconclusive`, `failed`, or `cancelled`. |
| `trigger` | What started the case: `question`, `incident`, `issue`, `finding`, `monitor`, `release`, `agent_session`, or `schedule`. |
| `incident_id` | Only the investigation of this incident. |
| `sort` | `newest` (default), `oldest`, or `updated`. |
| `limit` | 1 to 100. Default 50. |
| `offset` | The number of cases to skip. |

The response is `{ "investigations": [...], "total", "limit", "offset" }`.

## Read an investigation

```bash theme={null}
curl --url "https://api.squasher.ai/v1/projects/$SQUASHER_PROJECT_ID/investigations/$INVESTIGATION_ID" \
  --header "x-squasher-key: $SQUASHER_API_KEY"
```

The response has `investigation`, `entries`, and `actions`. Each timeline entry has a `sequence`
number, a `kind`, an `actor`, and a `payload`. The kinds are `hypothesis`, `evidence`, `action`,
`note`, `redirect`, and `status`. Add `after_sequence=<n>` to get only the entries after entry `n`.
Add `include_actions=false` to leave out the action proposals (`actions` is empty) when you poll;
read them with `actions.list`.

## Add a note, steer, or cancel

```bash theme={null}
curl --request POST \
  --url "https://api.squasher.ai/v1/projects/$SQUASHER_PROJECT_ID/investigations/$INVESTIGATION_ID/redirect" \
  --header "x-squasher-key: $SQUASHER_API_KEY" \
  --header "content-type: application/json" \
  --data '{ "text": "Check the database connection pool first." }'
```

* `notes` adds a note to the timeline. The body is `{ "text" }`. The response has status `201` and
  the new entry in `entry`.
* `redirect` records the direction, and Squasher continues the investigation in that direction. This
  also works after a diagnosis. The body is `{ "text" }`. The response has status `202`.
* `cancel` stops an active investigation. The body is optional: `{ "reason" }`.

Text is at most 4,000 characters. A reason is at most 2,000 characters.

## List actions

```bash theme={null}
curl --url "https://api.squasher.ai/v1/projects/$SQUASHER_PROJECT_ID/actions?status=proposed" \
  --header "x-squasher-key: $SQUASHER_API_KEY"
```

You can filter by `status`, `investigation_id`, and `incident_id`, and set `limit` (1 to 100,
default 50). The statuses are `proposed`, `approved`, `executing`, `unknown`, `succeeded`, `failed`,
`expired`, and `rejected`. `unknown` means Squasher sent the call but did not see the result. Squasher
does not run the action again; it reads the provider to settle the result.

```json theme={null}
{
  "actions": [
    {
      "id": "9d2e4f6a-3b1c-4e7d-8a5f-0c6b2d9e1a47",
      "status": "proposed",
      "provider": "railway",
      "action_id": "restart",
      "title": "Restart the checkout service",
      "target": { "kind": "railway_service", "id": "checkout", "label": "checkout" },
      "params": { "environment": "production" },
      "risk_class": "medium",
      "required_scope": "actions:approve",
      "investigation_id": "3f1c2b7a-8d4e-4a9b-b6c1-2e5f0a7d9c13",
      "incident_id": null,
      "expires_at": "2026-10-11T11:20:00.000Z",
      "precondition": null,
      "postcondition": null,
      "failure_reason": null
    }
  ]
}
```

The example leaves out some fields. See [Investigations](/features/investigations#supported-actions)
for the actions and their targets.

## Approve or reject an action

```bash theme={null}
curl --request POST \
  --url "https://api.squasher.ai/v1/projects/$SQUASHER_PROJECT_ID/actions/$ACTION_ID/approve" \
  --header "authorization: Bearer $SQUASHER_USER_TOKEN" \
  --header "content-type: application/json" \
  --data '{ "reason": "Restart is safe during the incident." }'
```

Approve runs the action at once. Squasher checks the precondition, calls the provider one time, and
checks the postcondition. The response has the action with its final `status`, `precondition`, and
`postcondition`. Reject uses the same body at `/reject`. The `reason` is optional.

When the result is `unknown`, settle it at `/resolve`. Squasher reads the provider first. When the
provider cannot tell, send your finding after you check the provider:

```json theme={null}
{ "outcome": "failed", "note": "No new deployment in Railway" }
```

`outcome` is `succeeded` or `failed`. `note` is optional. When the provider cannot tell and you send
no `outcome`, the response has status `409`.

## Errors

| Status | When |
| - | - |
| `400` | The body or a query parameter is not valid, or the body has no question and no subject. |
| `403` | The caller does not have the scope, or a decision came from an API key or a non-admin. |
| `404` | The project, investigation, subject, or action does not exist. |
| `409` | The investigation is finished or cancelled, the action was decided, or it is not unknown. |
| `410` | The action proposal expired. |

## TypeScript client and CLI

```typescript theme={null}
const { investigation } = await client.investigations.create({
  question: "Why did checkout errors increase after 10:00?",
});
const { entries, actions } = await client.investigations.get(investigation.id);
await client.investigations.redirect(investigation.id, "Check the database pool first.");
await client.actions.approve(actions[0].id, "Safe to run now.");
```

```bash theme={null}
squasher investigations start --project <project_id> --question "Why did checkout errors increase?"
squasher investigations list --project <project_id> --view active
squasher investigations get --project <project_id> <investigation_id>
squasher investigations note --project <project_id> <investigation_id> "Deploy at 10:02"
squasher investigations redirect --project <project_id> <investigation_id> "Check the database pool"
squasher investigations cancel --project <project_id> <investigation_id> --reason "Duplicate"
squasher actions list --project <project_id> --status proposed
squasher actions approve --project <project_id> <action_id>
squasher actions reject --project <project_id> <action_id> --reason "Not now"
squasher actions resolve --project <project_id> <action_id> --outcome failed
```

`squasher actions approve` and `squasher actions reject` ask you to confirm. Add `--yes` to skip the
prompt.

## Related guides

* [Investigations](/features/investigations)
* [Incidents API](/api-reference/incidents)
* [API keys](/api-reference/api-keys)


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