# Filters

Conditionally create events for a flow based on the request's body or headers.

One source often feeds several services that each care about a slice of the traffic. A filter on a flow decides whether a request becomes an event for that flow. A request that does not match is **not** delivered through that flow, but other flows on the same source are unaffected, and the request is still stored and counted as `filtered` on the source.

## How a filter is written

A filter has a `match` mode and a list of `conditions`.

```json
{
  "match": "all",
  "conditions": [
    { "path": "type", "op": "eq", "value": "invoice.paid" },
    { "path": "data.object.amount_paid", "op": "gte", "value": "10000" }
  ]
}
```

- `match: "all"` requires every condition to pass; `"any"` requires at least one.
- `path` points into the request: a dotted path into the JSON body (`data.object.currency`), with `[0]`, `[-1]` for the last element, or `[*]` for every element. Header values are available too, such as `$headers.x-github-event`.
- A filter has up to 20 conditions, and each value is up to 500 characters.

## Operators

| `op` | Passes when the value… |
|---|---|
| `eq` / `neq` | equals / does not equal `value` |
| `contains` / `not_contains` | contains / does not contain `value` |
| `starts_with` | starts with `value` |
| `in` | is one of a comma-separated list |
| `gt`, `gte`, `lt`, `lte` | compares numerically |
| `exists` / `not_exists` | is present / is missing (no `value` needed) |

With `[*]` in a path, a positive operator passes if **any** element matches, and a negative one passes only if **all** elements do.

## Examples

Deliver only `push` events from GitHub on the main branch:

```json
{ "match": "all", "conditions": [
  { "path": "$headers.x-github-event", "op": "eq", "value": "push" },
  { "path": "ref", "op": "eq", "value": "refs/heads/main" }
] }
```

Deliver failures and cancellations to an alerting service:

```json
{ "match": "any", "conditions": [
  { "path": "type", "op": "in", "value": "payment.failed, payment.canceled" }
] }
```

## Add a filter

In the dashboard, open the flow and choose **Filter**; the editor previews the result against the source's last request. Over the API, set `filter` when you [create](/api-reference/create-a-flow/) or [update](/api-reference/update-a-flow/) a flow, and send `null` to remove it.

> [!NOTE]
> Filters run on the request as the sender sent it, before the [transformation](/gateway/transformations/). Write paths against the original body, not the reshaped one.

## When a filter is not what you want

- To change the shape of the body, use a [transformation](/gateway/transformations/).
- To drop repeats, use [deduplication](/gateway/deduplication/).
- To hold events for later, use the flow's `delay_seconds`.