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

# Filters

Most `.list` endpoints accept an optional `filters` array in the JSON request body to narrow down the returned results. Each endpoint declares its own set of filters — the available keys and their expected value types are listed on the endpoint's API Reference page. Like every tipee API call, the examples below are `POST` requests with a JSON body (see [First steps](/guides-and-resources/first-steps)).

## Basic syntax

Every filter is an object with two required fields: a `key` identifying the filter, and a `value`. The filter keys declared by an endpoint follow the `<entity>.<field>` naming convention; the composite keys `or` and `and` described in [Combining filters](#combining-filters) are the only exception:

```json theme={null}
{
  "filters": [
    {
      "key": "<entity>.<field>",
      "value": "<value>"
    }
  ]
}
```

For example, on `/api/directory/tags.list`:

```
POST https://<instance>.tipee.net/api/directory/tags.list

Accept: application/json
Content-Type: application/json
Authorization: Bearer <YOUR_API_KEY>
Tipee-Version: <version>
```

```json theme={null}
{
  "filters": [
    {
      "key": "tag.name",
      "value": "billing"
    },
    {
      "key": "tag.with_disabled",
      "value": true
    }
  ]
}
```

This returns tags whose name contains "billing" (case-insensitive), including disabled ones.

## Combining filters

Filters at the top level of the `filters` array are combined with a logical **AND**. The same key may appear multiple times; each occurrence adds another condition.

To express alternatives, use the composite keys `or` and `and`, available on every endpoint that supports filters. Their `value` is an array of nested filters, and they can be nested inside each other without depth limit:

```json theme={null}
{
  "filters": [
    {
      "key": "activity.date_range",
      "value": "2026-01-01/2026-01-31"
    },
    {
      "key": "or",
      "value": [
        {
          "key": "activity.billable",
          "value": true
        },
        {
          "key": "and",
          "value": [
            {
              "key": "activity.has_remark",
              "value": true
            },
            {
              "key": "activity.project_name",
              "value": "Acme"
            }
          ]
        }
      ]
    }
  ]
}
```

This matches activities in January 2026 that are either billable, or have a remark and belong to a project whose name contains "Acme".

## Value shapes

The shape of `value` depends on the filter — the endpoint's API Reference documents the exact type for each key.

| Shape           | Behavior                                                        | Example                                                              |
| --------------- | --------------------------------------------------------------- | -------------------------------------------------------------------- |
| Scalar          | Comparison defined by the filter (equality, substring match, …) | `{ "key": "tag.name", "value": "billing" }`                          |
| Array           | Matches any of the listed values                                | `{ "key": "tag.ids", "value": ["872815618512410358"] }`              |
| Range string    | Matches values within or intersecting the range                 | `{ "key": "activity.date_range", "value": "2026-01-01/2026-01-31" }` |
| Operator object | You pick the comparison explicitly                              | See [Operator objects](#operator-objects)                            |

<Note>Duplicate array values are ignored, and some array filters accept `null` as an element to match entries without a value — for example resources not assigned to any project.</Note>

## Operator objects

Some filters take an object as `value`, letting you choose the comparison operator explicitly. The most common case is the attribute filters of `/api/directory/resources.list`, which target the configured attributes of a directory kind:

```json theme={null}
{
  "kind_id": "872815618512410358",
  "filters": [
    {
      "key": "resource.text",
      "value": {
        "attribute": "last_name",
        "operator": "starts_with",
        "value": "Dup"
      }
    },
    {
      "key": "resource.integer",
      "value": {
        "attribute": "children_count",
        "operator": "greater_than_or_equal",
        "value": 2
      }
    }
  ]
}
```

The allowed operators depend on the value type of the filter:

| Value type    | Operators                                                                                                  |
| ------------- | ---------------------------------------------------------------------------------------------------------- |
| Text          | `equals`, `not_equals`, `contains`, `not_contains`, `starts_with`, `ends_with`, `none`                     |
| Numeric       | `equals`, `not_equals`, `less_than`, `less_than_or_equal`, `greater_than`, `greater_than_or_equal`, `none` |
| Boolean       | `equals`, `not_equals`, `none`                                                                             |
| Choice / list | `in_list`, `not_in_list`, `none`                                                                           |
| Range         | `in_range`, `not_in_range`, `none`                                                                         |
| Date & time   | `equals`, `not_equals`, `from`, `until`, `none`                                                            |

<Note>The `none` operator matches entries where the attribute has no value at all. Omit the `value` property when using it — with any other operator, `value` is required.</Note>

For `resources.list`, the available attribute names come from `/api/directory/kinds.show`, which also indicates whether each attribute can be filtered or ordered.

## Data formats

| Type             | Format                             | Example                   |
| ---------------- | ---------------------------------- | ------------------------- |
| Identifier       | Numeric string                     | `"872815618512410358"`    |
| Date             | `YYYY-MM-DD`                       | `"2026-01-31"`            |
| Date & time      | `YYYY-MM-DDTHH:MM:SS`, no timezone | `"2026-01-31T17:30:00"`   |
| Date range       | `start/end`, inclusive             | `"2026-01-01/2026-01-31"` |
| Open-ended range | `-` on the unbounded side          | `"2026-01-01/-"`          |
| Relative range   | ISO 8601 period on one side        | `"2026-01-01/P1M"`        |
| Month-day range  | `--MM-DD/--MM-DD`                  | `"--11-01/--12-31"`       |
| Duration         | ISO 8601 duration                  | `"PT1H30M"`               |
| Boolean          | JSON boolean, not a string         | `true`                    |

## Common errors

| Status | Cause                                                                                                                                   |
| ------ | --------------------------------------------------------------------------------------------------------------------------------------- |
| `422`  | Unknown filter `key`, missing `key` or `value`, `null` value on a filter that does not accept it, `or`/`and` value that is not an array |
| `400`  | Malformed value: invalid date or range string, unknown enum value, wrong scalar type                                                    |

The response body contains a message describing the problem — see [Error Handling](/guides-and-resources/error-handling) for the general error format.
