---
title: "Filter"
description: "Narrow down collections using multiple AND/OR conditions on any field — supports nested paths, existence checks, and case sensitivity."
icon: "filter"
---

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
[
  { "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
[
  { "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>
