---
updatedAt: 2026-04-14T12:53:48.000Z
agentTools:
  projectIndex: https://developer.xentral.com/llms.txt
---

# V3 Filtering, Ordering & Pagination

Some resources in the Xentral V3 API support filtering, ordering, and pagination via query string parameters. Which fields and operators are available is specified per endpoint in the API documentation.

***

# Filtering

Filters are passed as indexed query parameters. All filter criteria are AND-combined. Each filter entry has three parts:

* `filter[n][key]` — the field to filter on
* `filter[n][op]` — the operator to apply
* `filter[n][value]` — the value to compare against

**Single filter:**

```
GET /api/v3/invoices?filter[0][key]=status&filter[0][op]=equals&filter[0][value]=released
```

**Multiple filters (AND-combined):**

```
GET /api/v3/invoices
  ?filter[0][key]=status&filter[0][op]=equals&filter[0][value]=released
  &filter[1][key]=totals.gross.amount&filter[1][op]=greaterThan&filter[1][value]=1000
```

> Nested fields are supported using dot notation, e.g. `dunningSettings.blocked`, `totals.gross.amount`.

## Operators

Not every operator is available for every field — the supported operators depend on the field type.

| Operator              | Applicable to                       | Description                    |
| :-------------------- | :---------------------------------- | :----------------------------- |
| `equals`              | string, number, date, boolean, enum | Exact match                    |
| `notEquals`           | string, number, date, boolean, enum | Does not match                 |
| `in`                  | string, number, ID, enum            | Value is in the given list     |
| `notIn`               | string, number, ID, enum            | Value is not in the given list |
| `contains`            | string                              | Substring match                |
| `notContains`         | string                              | Does not contain substring     |
| `startsWith`          | string                              | Starts with value              |
| `endsWith`            | string                              | Ends with value                |
| `greaterThan`         | number, date                        | Greater than value             |
| `greaterThanOrEquals` | number, date                        | Greater than or equal to value |
| `lessThan`            | number, date                        | Less than value                |
| `lessThanOrEquals`    | number, date                        | Less than or equal to value    |
| `isNull`              | all                                 | Field is null / not set        |
| `isNotNull`           | all                                 | Field is not null              |

## Filtering examples

Filter invoices by customer number containing "ACME":

```
GET /api/v3/invoices?filter[0][key]=customerNumber&filter[0][op]=contains&filter[0][value]=ACME
```

Filter by document date range:

```
GET /api/v3/invoices
  ?filter[0][key]=documentDate&filter[0][op]=greaterThanOrEquals&filter[0][value]=2025-01-01
  &filter[1][key]=documentDate&filter[1][op]=lessThanOrEquals&filter[1][value]=2025-03-31
```

Filter by a list of IDs:

```
GET /api/v3/invoices?filter[0][key]=sales.id&filter[0][op]=in&filter[0][value][0]=1&filter[0][value][1]=2&filter[0][value][2]=3
```

Filter by a boolean field:

```
GET /api/v3/invoices?filter[0][key]=dunningSettings.blocked&filter[0][op]=equals&filter[0][value]=true
```

> **Dates** should be provided in `YYYY-MM-DD` format.

***

# Ordering

Ordering is specified via the `sort` query parameter as a space-separated list of field names.

* **Ascending:** `fieldName`
* **Descending:** `-fieldName` (prefix with a minus sign)

Multiple fields are comma-separated. The order determines priority — the first field is the primary sort criterion.

**Single field, ascending:**

```
GET /api/v3/invoices?sort=documentDate
```

**Single field, descending:**

```
GET /api/v3/invoices?sort=-createdAt
```

**Multiple fields:**

```
GET /api/v3/invoices?sort=customerNumber,-documentDate
```

It is specified per endpoint which fields are sortable. If no `sort` parameter is provided, a default sort order is applied (typically by `id` ascending).

***

# Pagination

The V3 API supports three pagination strategies, selected via the **`X-Pagination`** request header. If the header is omitted, `simple` is used by default.

## `simple` (default)

```
X-Pagination: simple
```

Returns a page of results **without a total count**. More efficient than `table` because no `COUNT(*)` query is executed.

**Query parameters:**

| Parameter | Description                                            |
| :-------- | :----------------------------------------------------- |
| `page`    | Page number (default: `1`)                             |
| `perPage` | Items per page (default: `15`, max: endpoint-specific) |

**Response meta:** `current_page`, `per_page`, navigation links — no `total`.

```
GET /api/v3/invoices?page=1&perPage=25
```

> Use this when iterating through pages programmatically and a total count is not needed.

## `table`

```
X-Pagination: table
```

Returns a page of results **including the total count** of all matching records. Requires an additional `COUNT(*)` query.

**Query parameters:**

| Parameter | Description                                            |
| :-------- | :----------------------------------------------------- |
| `page`    | Page number (default: `1`)                             |
| `perPage` | Items per page (default: `15`, max: endpoint-specific) |

**Response meta:** `current_page`, `per_page`, `total`, `last_page`, navigation links.

```
GET /api/v3/invoices?page=1&perPage=25
X-Pagination: table
```

> Use this for paginated table UIs where users need to see the total number of results or navigate to a specific page.

## `cursor`

```
X-Pagination: cursor
```

Navigates via an opaque cursor string instead of page numbers. **No total count** is returned. Very efficient for large datasets as it avoids `OFFSET`-based queries.

**Query parameters:**

| Parameter | Description                                                       |
| :-------- | :---------------------------------------------------------------- |
| `cursor`  | Cursor value from the previous response (omit for the first page) |
| `perPage` | Items per page (default: `15`, max: endpoint-specific)            |

**Response meta:** `next_cursor`, `prev_cursor`.

**First page:**

```
GET /api/v3/invoices?perPage=25
X-Pagination: cursor
```

**Subsequent pages:**

```
GET /api/v3/invoices?cursor=eyJpZCI6MTAwfQ&perPage=25
X-Pagination: cursor
```

> Navigation is sequential only (next/previous) — jumping to an arbitrary page is not possible. Use this for exports or background data processing over large datasets.

## Pagination summary

|                         | `simple`           | `table`  | `cursor` |
| :---------------------- | :----------------- | :------- | :------- |
| Pagination style        | offset             | offset   | cursor   |
| Total count in response | no                 | **yes**  | no       |
| Jump to arbitrary page  | yes                | yes      | no       |
| Performance             | good               | moderate | **best** |
| `X-Pagination` header   | `simple` (default) | `table`  | `cursor` |

***

# Combining filter, sort & pagination

All three query features can be combined freely:

```
GET /api/v3/invoices
  ?filter[0][key]=status&filter[0][op]=equals&filter[0][value]=released
  &sort=-documentDate,customerNumber
  &page=1
  &perPage=50
X-Pagination: table
```