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

# Pagination

> How to paginate, sort, and filter LENS API (v2) endpoints that return tabular data using the offset-based AG-Grid request model.

The LENS API uses two pagination patterns depending on the endpoint type:

* **Offset-based (AG-Grid model)** — used by POST endpoints that return tabular data. Covered in detail on this page.
* **Typesense page/per\_page** — used by the `/search-public/*` endpoints. See the [Public Search](/api-lens/publicsearch/search-companies-get) group for query-string parameters.

## Offset-based pagination

Tabular endpoints (companies at an address, watchlist members, person companies, etc.) accept a POST request whose JSON body specifies the row range, sort order, and filters.

### Request body

```json theme={null}
{
  "startRow": 0,
  "endRow": 50,
  "sortModel": [
    { "colId": "companyName", "sort": "asc" }
  ],
  "filterModel": {}
}
```

| Field         | Type   | Description                                                    |
| ------------- | ------ | -------------------------------------------------------------- |
| `startRow`    | int    | Zero-based index of the first row to return                    |
| `endRow`      | int    | Zero-based index of the row **after** the last row (exclusive) |
| `sortModel`   | array  | Optional. Sorting instructions — see [Sorting](#sorting)       |
| `filterModel` | object | Optional. Server-side filters — see [Filtering](#filtering)    |

The page size is `endRow - startRow`. For example, `startRow: 0, endRow: 50` returns the first 50 rows.

### Response

```json theme={null}
{
  "success": true,
  "rows": [ ... ],
  "lastrow": -1
}
```

| Field     | Type  | Description                                                      |
| --------- | ----- | ---------------------------------------------------------------- |
| `success` | bool  | Whether the request succeeded                                    |
| `rows`    | array | The data rows for the requested range                            |
| `lastrow` | int   | Index of the last row in the dataset, or `-1` if more rows exist |

### How to paginate

Use `lastrow` to determine if there are more pages:

* `lastrow == -1` — more rows available, request the next page
* `lastrow >= 0` — this is the last page, `lastrow` is the total row count

Example — fetch all rows in pages of 100:

```bash theme={null}
# Page 1
curl -X POST "https://lens-api.tic.io/addresses/12345/companies" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "startRow": 0, "endRow": 100 }'
# → lastrow: -1 (more rows exist)

# Page 2
curl -X POST "https://lens-api.tic.io/addresses/12345/companies" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "startRow": 100, "endRow": 200 }'
# → lastrow: 142 (last page, 142 total rows)
```

## Sorting

Add a `sortModel` array to sort by one or more columns:

```json theme={null}
{
  "startRow": 0,
  "endRow": 50,
  "sortModel": [
    { "colId": "companyName", "sort": "asc" }
  ]
}
```

| Field   | Type   | Values                 |
| ------- | ------ | ---------------------- |
| `colId` | string | Column name to sort by |
| `sort`  | string | `asc` or `desc`        |

## Filtering

Add a `filterModel` object to filter results server-side. Each key is a column name; the value describes the filter.

### Text filter

```json theme={null}
{
  "filterModel": {
    "companyName": {
      "type": "contains",
      "filter": "Volvo",
      "filterType": "text"
    }
  }
}
```

### Number filter

```json theme={null}
{
  "filterModel": {
    "numberOfEmployees": {
      "type": "greaterThan",
      "filter": 100,
      "filterType": "number"
    }
  }
}
```

### Date range filter

```json theme={null}
{
  "filterModel": {
    "registrationDate": {
      "type": "inRange",
      "dateFrom": "2024-01-01",
      "dateTo": "2024-12-31",
      "filterType": "date"
    }
  }
}
```

### Set filter (match any of the values)

```json theme={null}
{
  "filterModel": {
    "localCompanyCode": {
      "filterType": "set",
      "values": ["AB", "HB"]
    }
  }
}
```

### Multiple conditions on the same column

```json theme={null}
{
  "filterModel": {
    "numberOfEmployees": {
      "operator": "AND",
      "filterType": "number",
      "conditions": [
        { "type": "greaterThan", "filter": 10, "filterType": "number" },
        { "type": "lessThan", "filter": 500, "filterType": "number" }
      ]
    }
  }
}
```

### Supported filter operators

| Operator      | Types        | Description                                 |
| ------------- | ------------ | ------------------------------------------- |
| `equals`      | text, number | Exact match                                 |
| `notEqual`    | text, number | Not equal                                   |
| `contains`    | text         | Substring match                             |
| `startsWith`  | text         | Starts with                                 |
| `endsWith`    | text         | Ends with                                   |
| `greaterThan` | number, date | Greater than                                |
| `lessThan`    | number, date | Less than                                   |
| `inRange`     | date         | Between `dateFrom` and `dateTo` (inclusive) |
| `blank`       | all          | Value is null                               |
| `notBlank`    | all          | Value is not null                           |

### Combining conditions

Use the `operator` field with `"AND"` or `"OR"` to combine multiple conditions on the same column.

## Endpoints using this pattern

These POST endpoints accept the pagination request body described above:

| Endpoint                                | Description                                |
| --------------------------------------- | ------------------------------------------ |
| `POST /addresses/{id}/companies`        | Companies at an address                    |
| `POST /addresses/{id}/workplaces`       | Workplaces at an address                   |
| `POST /addresses/{id}/persons`          | Persons at an address                      |
| `POST /properties/se/{uuid}/companies`  | Companies at a property                    |
| `POST /properties/se/{uuid}/workplaces` | Workplaces at a property                   |
| `POST /persons/{id}/companies`          | Companies where person is a representative |
| `POST /persons/{id}/beneficial-owners`  | Beneficial ownership positions             |
| `POST /watchlists/{id}/companies`       | Company members of a watchlist             |
| `POST /watchlists/{id}/persons`         | Person members of a watchlist              |
| `POST /watchlists/{id}/addresses`       | Address members of a watchlist             |
| `POST /watchlists/{id}/properties`      | Property members of a watchlist            |
| `POST /watchlists/{id}/vehicles`        | Vehicle members of a watchlist             |
| `POST /watchlists/{id}/events`          | Watchlist events                           |
| `POST /orders`                          | Your document orders                       |
| `POST /team/orders`                     | Team document orders                       |
| `POST /team/exports`                    | Team exports                               |
