# Filtering

Find exactly the records you need with search filters.

Search and count endpoints take a `filters` list. Each filter names a field, a `mode` and a `value`:

```json
{
  "fields": ["id", "fullName"],
  "filters": [
    { "city": { "mode": "EQEM", "value": ["Limassol"] } }
  ],
  "limit": 25
}
```

## Combining filters

Fields inside one item must **all** match (AND). Separate items are alternatives (OR).

```json
{
  "filters": [
    { "city": { "mode": "EQEM", "value": ["Limassol"] }, "doNotContact": { "mode": "EQ", "value": false } },
    { "city": { "mode": "EQEM", "value": ["Paphos"] } }
  ]
}
```

This finds clients in Limassol who can be contacted, plus everyone in Paphos.

## Modes

| Mode | Works on | Meaning |
|---|---|---|
| `EQ` | All | Text: contains any of the values, ignoring case. Other types: equal to. |
| `EX` | All | The opposite of `EQ`. Text filters also match empty fields. |
| `EQEM` | Text | Exactly equal to one of the values. |
| `EXEM` | Text | Not exactly equal to any of the values. |
| `RG` | Numbers, dates | Between two values: `[from, to]`. |
| `NRG` | Date and time | Not between two values. |
| `GT`, `GTE` | Numbers, dates | Greater than, or greater than or equal to. |
| `LT`, `LTE` | Numbers, dates | Less than, or less than or equal to. |
| `EM` | All | The field is empty. Send `null` as the value. |
| `NEM` | All | The field is not empty. Send `null` as the value. |

> [!WARNING]
> For text modes, always send `value` as a list, even with one value. A plain text value is read one character at a time and matches the wrong records.

> [!TIP]
> To match an email or a name exactly, use `EQEM`. `EQ` matches any part of the text, so `ann` also finds `Joanna`.
