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

# Filter

> Narrow down collections using multiple AND/OR conditions on any field — supports nested paths, existence checks, and case sensitivity.

The **Filter** step takes a JSON array and returns only the items that match your conditions. Use it to extract relevant records from an API response, remove incomplete entries before passing data to a model, or isolate items that meet specific business rules.

You define one or more conditions, choose whether **all** (AND) or **any** (OR) must match, and the step outputs the filtered array — same structure, fewer items.

***

## Configuration

<Steps>
  <Step title="Input">
    An expression that resolves to a JSON array — for example, `{{Steps.API_Call.Output.Body.data.orders}}`.
  </Step>

  <Step title="Logical operator">
    **AND** (default) — an item must match every condition to be kept.
    **OR** — an item is kept if it matches at least one condition.
  </Step>

  <Step title="Conditions">
    One or more rules to evaluate against each item. Each condition has:

    * **Field path** — dot-notation path to the field (e.g., `status`, `address.city`). Leave empty to filter by the item value itself (useful for arrays of strings or numbers).
    * **Operator** — the comparison to apply.
    * **Value** — the value to compare against. Supports expressions like `{{Variables.threshold}}`. Not required for existence and emptiness operators.
    * **Case sensitive** — toggle for string comparisons (off by default).
  </Step>
</Steps>

***

## Operators

### Value operators

These require a comparison value.

| Operator                  | What it checks                                                      |
| ------------------------- | ------------------------------------------------------------------- |
| **Equals**                | Field value matches exactly (supports numeric and boolean coercion) |
| **Not Equals**            | Field value does not match                                          |
| **Greater Than**          | Field > Value (numeric first, then lexicographic fallback)          |
| **Greater Than or Equal** | Field ≥ Value                                                       |
| **Less Than**             | Field \< Value                                                      |
| **Less Than or Equal**    | Field ≤ Value                                                       |
| **Contains**              | Field string includes Value as a substring                          |
| **Not Contains**          | Field string does not include Value                                 |
| **Starts With**           | Field string begins with Value                                      |
| **Ends With**             | Field string ends with Value                                        |

### Existence operators

These do not require a value — they check the field itself.

| Operator         | What it checks                                               |
| ---------------- | ------------------------------------------------------------ |
| **Exists**       | The field is present on the item (even if its value is null) |
| **Not Exists**   | The field is not present on the item                         |
| **Is Empty**     | The field is null, whitespace, or an empty array             |
| **Is Not Empty** | The field has a non-empty value                              |

***

## Field paths

Use dot notation to reach nested fields:

| Field path           | Reaches                                                              |
| -------------------- | -------------------------------------------------------------------- |
| `status`             | `item.status`                                                        |
| `address.city`       | `item.address.city`                                                  |
| `user.profile.email` | `item.user.profile.email`                                            |
| *(empty)*            | The item itself — useful for primitive arrays like `["a", "b", "c"]` |

<Info>
  If a field path does not exist on an item, the condition evaluates to `false` for most operators. The exception is **Not Exists**, which returns `true` for missing fields.
</Info>

***

## Type coercion

The Filter step applies smart comparison:

1. **Numeric fields** — if both the field value and the condition value parse as numbers, a numeric comparison is used. This means `"10"` is correctly treated as less than `"9"` in numeric mode, unlike string comparison.
2. **Boolean fields** — `true` / `false` values are compared as booleans.
3. **String fallback** — if neither numeric nor boolean applies, string comparison is used with the case sensitivity toggle.

***

## Output

The step returns a **JSON array** containing only the items that passed your conditions. The original order is preserved.

```
{{Steps.Filter.Value}}  →  [ ...matching items... ]
```

If no items match, the output is an empty array `[]`.

***

## Use case: extract overdue invoices from an API

A finance agent fetches all invoices from an accounting API and needs to isolate the ones that are overdue and above a minimum amount before passing them to a model for follow-up email drafting.

**Agent flow:**

```
Input → Fetch Invoices (HTTP) → Filter → Draft Emails (AI Model)
```

**Filter configuration:**

| Setting          | Value                                                |
| ---------------- | ---------------------------------------------------- |
| Input            | `{{Steps.Fetch_Invoices.Output.Body.data.invoices}}` |
| Logical operator | **AND**                                              |

**Conditions:**

| # | Field path      | Operator     | Value     | Case sensitive |
| - | --------------- | ------------ | --------- | -------------- |
| 1 | `status`        | Equals       | `overdue` | Off            |
| 2 | `amount`        | Greater Than | `500`     | —              |
| 3 | `contact.email` | Is Not Empty | —         | —              |

**What happens at runtime:**

Given this input:

```json theme={null}
[
  { "id": "INV-001", "status": "overdue", "amount": 1200, "contact": { "email": "jane@acme.com" } },
  { "id": "INV-002", "status": "paid", "amount": 800, "contact": { "email": "bob@corp.io" } },
  { "id": "INV-003", "status": "overdue", "amount": 300, "contact": { "email": "sue@example.com" } },
  { "id": "INV-004", "status": "overdue", "amount": 950, "contact": {} }
]
```

The Filter step returns:

```json theme={null}
[
  { "id": "INV-001", "status": "overdue", "amount": 1200, "contact": { "email": "jane@acme.com" } }
]
```

* INV-002 is excluded: status is `paid` (fails condition 1)
* INV-003 is excluded: amount is 300, below the 500 threshold (fails condition 2)
* INV-004 is excluded: `contact.email` is empty (fails condition 3)

The AI Model step downstream receives only the qualifying invoice and drafts a follow-up email.

***

## Tips

<Tip>
  Use **OR** logic when you want to catch multiple categories at once. For example, to find invoices that are either overdue **or** disputed, set the logical operator to OR and add two conditions on the `status` field.
</Tip>

<Tip>
  Chain a Filter step before a [Sort](/building-and-deploying-agents/agent-basics/sort-step) step to first narrow down the data, then order the results. This keeps token usage low when the sorted output is passed to a model.
</Tip>

<Warning>
  The input must be a JSON **array**. If your expression resolves to a single object or a primitive value, the step throws an error. If your upstream step returns a JSON object with an array inside it, reference the array field directly — for example, `{{Steps.API.Output.Body.data.items}}` instead of `{{Steps.API.Output.Body}}`.
</Warning>
