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

# Pagination, Sorting, and Filtering

All list endpoints in the Monaco Public API (`POST /v1/{entity}/list`) accept a JSON request body that controls pagination, sorting, and filtering.

```json theme={null}
{
  "filters": [],
  "sort": "-created_at",
  "page": 1,
  "page_size": 50
}
```

***

## Pagination

| Field       | Type | Default | Min | Max | Description             |
| ----------- | ---- | ------- | --- | --- | ----------------------- |
| `page`      | int  | 1       | 1   | --  | Page number (1-indexed) |
| `page_size` | int  | 50      | 1   | 500 | Results per page        |

Every list response includes a `pagination` object:

```json theme={null}
{
  "data": [ ... ],
  "pagination": {
    "page": 1,
    "page_size": 50,
    "total_count": 142,
    "total_pages": 3
  },
  "meta": { ... }
}
```

| Field         | Type | Description                         |
| ------------- | ---- | ----------------------------------- |
| `page`        | int  | The page you requested              |
| `page_size`   | int  | The page size you requested         |
| `total_count` | int  | Total matching records across pages |
| `total_pages` | int  | Total number of pages               |

### Iterating through pages

To fetch all records, increment `page` until `page >= total_pages`:

```bash theme={null}
# Page 1
curl -X POST .../v1/accounts/list \
  -H "x-monaco-api-key: $KEY" -H "Content-Type: application/json" \
  -d '{"page": 1, "page_size": 100}'

# Response includes pagination.total_pages = 3

# Page 2
curl -X POST .../v1/accounts/list \
  -H "x-monaco-api-key: $KEY" -H "Content-Type: application/json" \
  -d '{"page": 2, "page_size": 100}'

# Page 3 (final)
curl -X POST .../v1/accounts/list \
  -H "x-monaco-api-key: $KEY" -H "Content-Type: application/json" \
  -d '{"page": 3, "page_size": 100}'
```

***

## Sorting

Pass a field key in `sort`. Prefix with `-` for descending order. The default is `-created_at` (newest first) for most objects.

```json theme={null}
{"sort": "name"}           // A → Z
{"sort": "-name"}          // Z → A
{"sort": "created_at"}     // oldest first
{"sort": "-created_at"}    // newest first
```

Not every field supports sorting. Attempting to sort by an unsupported field returns a `422` error. Use the field schemas endpoint to discover sortable fields.

***

## Filtering

Filters are provided as either a flat array of rules (implicitly ANDed) or a recursive filter expression for complex AND/OR logic.

### Simple filters

Pass an array of rules. All rules are implicitly ANDed together.

Each rule has three properties:

| Property    | Type   | Required | Description                                          |
| ----------- | ------ | -------- | ---------------------------------------------------- |
| `field`     | string | yes      | The field key to filter on                           |
| `condition` | string | yes      | The comparison operator                              |
| `value`     | any    | no       | The value to compare against (omit for empty checks) |

```json theme={null}
{
  "filters": [
    { "field": "status", "condition": "is", "value": "active" },
    {
      "field": "created_at",
      "condition": "is_after",
      "value": "2025-01-01T00:00:00Z"
    }
  ]
}
```

### Complex filters (AND / OR)

For OR logic or nested conditions, pass a filter **expression** object instead of an array. An expression has:

| Property   | Type   | Required | Description                                                         |
| ---------- | ------ | -------- | ------------------------------------------------------------------- |
| `operator` | string | no       | `"and"` or `"or"` — how to combine the filters. Defaults to `"and"` |
| `filters`  | array  | yes      | Array of filter rules and/or nested filter expressions              |

Expressions can be nested to arbitrary depth, letting you build trees of AND/OR logic.

**Example — OR across two conditions:**

```json theme={null}
{
  "filters": {
    "operator": "or",
    "filters": [
      { "field": "status", "condition": "is", "value": "active" },
      { "field": "status", "condition": "is", "value": "pending" }
    ]
  }
}
```

**Example — OR with a nested AND group:**

```json theme={null}
{
  "filters": {
    "operator": "or",
    "filters": [
      { "field": "status", "condition": "is", "value": "active" },
      {
        "operator": "and",
        "filters": [
          { "field": "name", "condition": "contains", "value": "Acme" },
          {
            "field": "created_at",
            "condition": "is_after",
            "value": "2025-01-01T00:00:00Z"
          }
        ]
      }
    ]
  }
}
```

### Common conditions

| Condition      | Value required | Description                   |
| -------------- | -------------- | ----------------------------- |
| `is`           | yes            | Exact match OR exists in list |
| `is_not`       | yes            | Not equal                     |
| `equals`       | yes            | Exact match                   |
| `contains`     | yes            | Substring match               |
| `not_contains` | yes            | Substring exclusion           |
| `is_empty`     | no             | Field is null or empty        |
| `is_not_empty` | no             | Field has a value             |
| `is_before`    | yes            | Date is before value          |
| `is_after`     | yes            | Date is after value           |

The exact set of conditions available depends on the field type. Use the **Field Schemas** endpoint to discover them.

### Enum field values

For enum fields (e.g., status, stage), use the field's key value when filtering or sorting — not the human-readable display name. You can find the valid keys in the enum\_field\_settings.allowed\_values array
returned by the Field Schemas endpoint.

```
// Correct — uses the key
{"field": "status", "condition": "is", "value": "active"}

// Incorrect — uses the display name
{"field": "status", "condition": "is", "value": "Active"}
```

### Date values

Date filter values should be ISO 8601 strings. Trailing `Z` (UTC) is supported:

```json theme={null}
{"field": "created_at", "condition": "greater_than", "value": "2025-06-01T00:00:00Z"}
```

***

## Custom fields in sorting and filtering

Custom fields (prefixed with `custom_field_` in responses) can be used in `sort` and `filters` using their full key:

```json theme={null}
{
  "sort": "-custom_field_cf_arr",
  "filters": [
    {"field": "custom_field_cf_industry_vertical", "condition": "is", "value": "FinTech"}
  ]
}
```

***

## Discovering sortable and filterable fields

Use the **Field Schemas** endpoint to discover which fields support sorting and filtering, and which conditions each field accepts:

```text theme={null}
GET /v1/schemas/{entity}
```

Where `{entity}` is one of: `accounts`, `contacts`, `opportunities`, `tasks`, or `meetings`.
