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

# Ingest rules API

> List, add, change, order, and remove the ingest rules of a project, and preview the volume and saving of a rule.

Ingest rules drop or sample logs, spans, and metric points before Squasher stores them. Squasher
checks the rules of a project in order, and the first enabled rule that matches a row decides.
Dropped data is not stored and not billed. Changes apply within about 60 seconds. See
[Ingest rules](https://docs.squasher.ai/features/ingest-rules.md) for the conditions, sampling, and error protection.

Fields use camelCase.

## Operations

| Operation | Method and path | Access | Purpose |
| - | - | - | - |
| `ingestRules.list` | `GET /v1/projects/{project_id}/ingest-rules` | `errors:read` | List the rules in order, with their 7-day effect. |
| `ingestRules.create` | `POST /v1/projects/{project_id}/ingest-rules` | `errors:write` | Add a rule. |
| `ingestRules.update` | `PATCH /v1/projects/{project_id}/ingest-rules/{rule_id}` | `errors:write` | Change a rule, turn it off, or move it. |
| `ingestRules.delete` | `DELETE /v1/projects/{project_id}/ingest-rules/{rule_id}` | `errors:write` | Remove a rule. |
| `ingestRules.reorder` | `POST /v1/projects/{project_id}/ingest-rules/reorder` | `errors:write` | Set the order of all the rules. |
| `ingestRules.preview` | `POST /v1/projects/{project_id}/ingest-rules/preview` | `errors:read` | Volume and saving of a draft rule. Writes nothing. |

## List the rules

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

```json theme={null}
{
  "rules": [
    {
      "id": "6f1c2a9e-4b7d-4e8a-9c3f-1d2e5a7b8c90",
      "projectId": "7063a770-8cc6-4284-b5f9-c0cb19e6fa79",
      "name": "Health checks",
      "position": 0,
      "enabled": true,
      "signal": "traces",
      "action": "drop",
      "samplePercent": null,
      "match": {
        "service": null,
        "severities": [],
        "spanName": "/health",
        "metricName": null,
        "attributes": []
      },
      "includeErrors": false,
      "createdAt": "2026-10-30T09:00:00.000Z",
      "updatedAt": "2026-10-30T09:00:00.000Z",
      "measured": {
        "windowDays": 7,
        "matchedRows": 1200000,
        "matchedBytes": 2400000000,
        "droppedRows": 1199000,
        "droppedBytes": 2398000000,
        "keptRows": 1000,
        "keptBytes": 2000000,
        "saving": {
          "planId": "pro",
          "droppedBytesPerMonth": 10277142857,
          "ingestCents": 0,
          "storageCents": 0,
          "storageIsEstimate": true,
          "totalCents": 0,
          "includedBytes": 100000000000,
          "projectedMonthBytes": 64000000000,
          "note": "Telemetry stays within the plan allowance of 100 GB a month, so the ingest saving is 0. Dropped data does not count toward the allowance."
        }
      }
    }
  ]
}
```

`position` is the evaluation order, 0 first. `measured` counts what the rule did over the last 7
days, in billing bytes. `kept` counts matched rows that the rule kept: the sampled share and
protected error rows. The `saving` values are examples; Squasher reads them from your plan.

## Add a rule

| Field | Description |
| - | - |
| `name` | Required. 1 to 120 characters. |
| `signal` | Required. `logs`, `traces`, or `metrics`. |
| `action` | Required. `drop` or `sample`. |
| `samplePercent` | Required for `sample`: the share of matching rows to keep, 0 to 100. Ignored for `drop`. |
| `match` | The conditions: `service`, `severities` (logs), `spanName` (traces), `metricName` (metrics), and `attributes`. All must match. |
| `includeErrors` | Default `false`: error spans and error logs are kept even when the rule matches them. |
| `enabled` | Default `true`. |
| `position` | Where to put the rule, 0 first. Default: last. |

Each item of `match.attributes` is `{ "key", "op", "value" }`. `op` is `eq` (exact text) or `regex`
(an RE2 search, up to 256 characters, no lookaround or backreferences). The key is looked up in the
resource attributes, then in the record attributes.

```bash theme={null}
curl --request POST \
  --url "https://api.squasher.ai/v1/projects/$SQUASHER_PROJECT_ID/ingest-rules" \
  --header "x-squasher-key: $SQUASHER_API_KEY" \
  --header "content-type: application/json" \
  --data '{
    "name": "Debug logs of the worker",
    "signal": "logs",
    "action": "sample",
    "samplePercent": 10,
    "match": { "service": "worker", "severities": ["debug", "trace"] }
  }'
```

The response has status `201` and the new rule. The rule applies within about 60 seconds.

## Change a rule

Send only the fields that change. Fields of `match` merge with the saved conditions. To remove a
condition, set it to `null` (or `[]` for `severities` and `attributes`).

```bash theme={null}
curl --request PATCH \
  --url "https://api.squasher.ai/v1/projects/$SQUASHER_PROJECT_ID/ingest-rules/$RULE_ID" \
  --header "x-squasher-key: $SQUASHER_API_KEY" \
  --header "content-type: application/json" \
  --data '{ "enabled": false }'
```

The response has the changed rule.

## Order the rules

Send every rule ID of the project once, first rule first.

```bash theme={null}
curl --request POST \
  --url "https://api.squasher.ai/v1/projects/$SQUASHER_PROJECT_ID/ingest-rules/reorder" \
  --header "x-squasher-key: $SQUASHER_API_KEY" \
  --header "content-type: application/json" \
  --data '{ "ruleIds": ["'"$SECOND_ID"'", "'"$FIRST_ID"'"] }'
```

The response has the rules in the new order.

## Remove a rule

```bash theme={null}
curl --request DELETE \
  --url "https://api.squasher.ai/v1/projects/$SQUASHER_PROJECT_ID/ingest-rules/$RULE_ID" \
  --header "x-squasher-key: $SQUASHER_API_KEY"
```

The response has status `204`. Within about 60 seconds, the rows of the rule are stored again, or
the next matching rule applies.

## Preview a rule

The preview takes the same body as a new rule and writes nothing. Add `ruleId` to test changes to a
saved rule in its place. Rows that an earlier enabled rule matches are not counted, because that
rule decides them first. The preview works on every plan.

```bash theme={null}
curl --request POST \
  --url "https://api.squasher.ai/v1/projects/$SQUASHER_PROJECT_ID/ingest-rules/preview" \
  --header "x-squasher-key: $SQUASHER_API_KEY" \
  --header "content-type: application/json" \
  --data '{ "name": "Health checks", "signal": "traces", "action": "drop", "match": { "spanName": "/health" } }'
```

```json theme={null}
{
  "windowDays": 7,
  "matchedRows": 1180000,
  "matchedBytes": 2350000000,
  "droppedShare": 0.998,
  "source": "usage_daily: billing bytes and rows of traces for the last 7 days, times the matched share of 20000 rows from 28 time slices over 7 days in ClickHouse (observability traces tables, rows matched by earlier rules excluded)",
  "saving": {
    "planId": "pro",
    "droppedBytesPerMonth": 10050642857,
    "ingestCents": 0,
    "storageCents": 0,
    "storageIsEstimate": true,
    "totalCents": 0,
    "includedBytes": 100000000000,
    "projectedMonthBytes": 64000000000,
    "note": "Telemetry stays within the plan allowance of 100 GB a month, so the ingest saving is 0. Dropped data does not count toward the allowance."
  }
}
```

`matchedRows` and `matchedBytes` are estimates: the project's billed rows and bytes of the signal
over the last 7 days, times the share of a bounded sample of stored rows that the rule matches.
`droppedShare` is the share of the matched bytes the rule would drop: 1 for `drop`, `1 -
samplePercent / 100` for `sample`, less the error rows when `includeErrors` is `false`. `source`
names the data behind the estimate.

## The saving

`saving` is the monthly money effect of the dropped bytes, from your plan's current prices.
Dropped data is not billed, so:

* `ingestCents` is the telemetry charge of the month with the dropped bytes minus the charge
  without them. It is 0 while your telemetry stays within `includedBytes`; `note` then says so.
* `storageCents` is an estimate of the storage charge of the data that is no longer stored.
  `storageIsEstimate` is always `true`.
* `projectedMonthBytes` is your organization's telemetry for a month at its recent rate.
* `droppedBytesPerMonth` is the 7-day dropped bytes times 30/7.

## Errors

| Status | When |
| - | - |
| `400` | A field is not valid: a pattern with unsupported syntax, a `sample` rule without `samplePercent`, or a condition of another signal. |
| `403` | The key does not have the necessary access to the project. |
| `404` | No rule of this project has the given ID. |
| `409` | The project already has 100 rules, or `ruleIds` does not name every rule exactly once. |

## TypeScript client and CLI

```typescript theme={null}
const preview = await client.ingestRules.preview({
  name: "Health checks",
  signal: "traces",
  action: "drop",
  match: { spanName: "/health" },
});
const rule = await client.ingestRules.create({
  name: "Health checks",
  signal: "traces",
  action: "drop",
  match: { spanName: "/health" },
});
const { rules } = await client.ingestRules.list();
await client.ingestRules.update(rule.id, { enabled: false });
await client.ingestRules.delete(rule.id);
```

```bash theme={null}
squasher ingest-rules list --project <project_id>
squasher ingest-rules preview --project <project_id> --name "Health" --signal traces --action drop --span-name /health
```

The CLI also has `squasher ingest-rules create`, `update`, `reorder`, and `delete`. For their flags,
see the [CLI reference](https://docs.squasher.ai/integrations/cli-reference.md).

## Related guides

* [Ingest rules](https://docs.squasher.ai/features/ingest-rules.md)
* [Usage and budgets](https://docs.squasher.ai/features/usage-and-budgets.md)


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