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

# Filtering

> Narrow list endpoints with bracket-notation query filters.

Every list endpoint supports filtering through query parameters in the form `filter[<field>][<operator>]=<value>`. Multiple filters combine with **AND**.

```bash theme={null}
curl -G "https://api.nomos.energy/customers" \
  -H "Authorization: Bearer ${ACCESS_TOKEN}" \
  --data-urlencode "filter[type][eq]=residential" \
  --data-urlencode "filter[created_at][gte]=2024-01-01T00:00:00Z"
```

The endpoint reference lists each filterable field and which operators it accepts. Available operators are determined by the field's type. Filters that name an unknown field or use a disallowed operator are silently ignored, so a typo'd field name returns the unfiltered list rather than an error.

## Operators by field type

<Tabs>
  <Tab title="String">
    | Operator      | Description                 | Example                                 |
    | ------------- | --------------------------- | --------------------------------------- |
    | `eq`          | Exact match                 | `filter[email][eq]=john@example.com`    |
    | `ne`          | Not equal                   | `filter[status][ne]=cancelled`          |
    | `in`          | Comma-separated list        | `filter[status][in]=active,pending`     |
    | `is_null`     | Null check (`true`/`false`) | `filter[deleted_at][is_null]=true`      |
    | `contains`    | Case-insensitive contains   | `filter[last_name][contains]=mueller`   |
    | `starts_with` | Case-insensitive prefix     | `filter[email][starts_with]=john`       |
    | `ends_with`   | Case-insensitive suffix     | `filter[email][ends_with]=@example.com` |
  </Tab>

  <Tab title="Number">
    | Operator  | Description           | Example                         |
    | --------- | --------------------- | ------------------------------- |
    | `eq`      | Equal to              | `filter[amount][eq]=100`        |
    | `ne`      | Not equal             | `filter[amount][ne]=0`          |
    | `gt`      | Greater than          | `filter[amount][gt]=100`        |
    | `gte`     | Greater than or equal | `filter[amount][gte]=100`       |
    | `lt`      | Less than             | `filter[amount][lt]=1000`       |
    | `lte`     | Less than or equal    | `filter[amount][lte]=1000`      |
    | `in`      | Comma-separated list  | `filter[amount][in]=10,20,30`   |
    | `is_null` | Null check            | `filter[amount][is_null]=false` |
  </Tab>

  <Tab title="Date">
    Dates must be ISO 8601 with timezone.

    | Operator  | Description  | Example                                        |
    | --------- | ------------ | ---------------------------------------------- |
    | `gte`     | On or after  | `filter[created_at][gte]=2024-01-01T00:00:00Z` |
    | `lte`     | On or before | `filter[created_at][lte]=2024-12-31T23:59:59Z` |
    | `is_null` | Null check   | `filter[terminated_at][is_null]=true`          |
  </Tab>

  <Tab title="Boolean">
    | Operator  | Description      | Example                              |
    | --------- | ---------------- | ------------------------------------ |
    | `eq`      | `true` / `false` | `filter[is_verified][eq]=true`       |
    | `is_null` | Null check       | `filter[is_verified][is_null]=false` |
  </Tab>

  <Tab title="Enum">
    | Operator  | Description          | Example                             |
    | --------- | -------------------- | ----------------------------------- |
    | `eq`      | Exact match          | `filter[status][eq]=active`         |
    | `ne`      | Not equal            | `filter[status][ne]=cancelled`      |
    | `in`      | Comma-separated list | `filter[status][in]=active,pending` |
    | `is_null` | Null check           | `filter[status][is_null]=true`      |

    The endpoint reference lists the allowed values for each enum field.
  </Tab>
</Tabs>

## Common patterns

### Filter by date range

```bash theme={null}
curl -G "https://api.nomos.energy/subscriptions" \
  -H "Authorization: Bearer ${ACCESS_TOKEN}" \
  --data-urlencode "filter[created_at][gte]=2024-01-01T00:00:00Z" \
  --data-urlencode "filter[created_at][lte]=2024-01-31T23:59:59Z"
```

### Filter by multiple values

```bash theme={null}
curl -G "https://api.nomos.energy/customers" \
  -H "Authorization: Bearer ${ACCESS_TOKEN}" \
  --data-urlencode "filter[status][in]=active,pending"
```

### Search by substring

```bash theme={null}
curl -G "https://api.nomos.energy/customers" \
  -H "Authorization: Bearer ${ACCESS_TOKEN}" \
  --data-urlencode "filter[last_name][contains]=mueller"
```

### Exclude terminated records

```bash theme={null}
curl -G "https://api.nomos.energy/subscriptions" \
  -H "Authorization: Bearer ${ACCESS_TOKEN}" \
  --data-urlencode "filter[terminated_at][is_null]=true"
```

### Combine with pagination

Pass the same filter parameters with each page when [paginating](/api-references/pagination):

```bash theme={null}
curl -G "https://api.nomos.energy/subscriptions" \
  -H "Authorization: Bearer ${ACCESS_TOKEN}" \
  --data-urlencode "filter[status][eq]=active" \
  --data-urlencode "limit=20" \
  --data-urlencode "cursor=${NEXT_PAGE}"
```

<Note>
  Malformed filter syntax or invalid values return `400 BAD_REQUEST` with a
  message naming the offending parameter. See [Errors](/api-references/errors)
  for the full envelope.
</Note>
