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

# Pagination

> How to paginate lists in the Connecta DESK API with page and perPage, and how to use hasMore to know whether there are more pages.

Every list `GET` is paginated. You pick the page with two query parameters, and the `meta` in the
response tells you whether there are more pages.

<ParamField query="page" type="integer" default="1">
  Page number, starting at 1. An invalid value or one lower than 1 falls back to the default.
</ParamField>

<ParamField query="perPage" type="integer" default="20">
  Number of items per page. The default limit is 100. If you ask for more, you get 100, with no
  error.
</ParamField>

```bash theme={null}
curl --request GET \
  --url "$CONNECTA_URL/contacts?page=2&perPage=50" \
  --header "Authorization: Bearer $CONNECTA_TOKEN"
```

## The meta

```json theme={null}
{
  "data": [ "…50 contacts…" ],
  "meta": { "page": 2, "perPage": 50, "hasMore": true }
}
```

<ResponseField name="page" type="integer">
  The page you received.
</ResponseField>

<ResponseField name="perPage" type="integer">
  Number of items per page actually applied, with the limit already taken into account.
</ResponseField>

<ResponseField name="hasMore" type="boolean">
  `true` when there are records after this page.
</ResponseField>

## Total count

The `meta` does not report the total number of records or the total number of pages. To find out
whether there is another page, use `hasMore`.

If you need to show a count on screen, add up the items you receive as you go through the pages.

## Going through everything

To read every record, keep advancing `page` while `hasMore` is `true`.

<CodeGroup>
  ```javascript Node.js theme={null}
  async function* paginate(path, params = {}) {
    let page = 1;

    for (;;) {
      const query = new URLSearchParams({ ...params, page, perPage: 100 });
      const res = await fetch(`${process.env.CONNECTA_URL}${path}?${query}`, {
        headers: { Authorization: `Bearer ${process.env.CONNECTA_TOKEN}` }
      });

      if (!res.ok) throw new Error(`${res.status} on ${path}`);

      const { data, meta } = await res.json();
      yield* data;

      if (!meta.hasMore) return;
      page += 1;
    }
  }

  for await (const contact of paginate('/contacts', { search: 'silva' })) {
    console.log(contact.id, contact.name);
  }
  ```

  ```python Python theme={null}
  import os, requests

  def paginate(path, **params):
      page = 1

      while True:
          res = requests.get(
              f"{os.environ['CONNECTA_URL']}{path}",
              params={**params, "page": page, "perPage": 100},
              headers={"Authorization": f"Bearer {os.environ['CONNECTA_TOKEN']}"},
          )
          res.raise_for_status()

          body = res.json()
          yield from body["data"]

          if not body["meta"]["hasMore"]:
              return
          page += 1

  for contact in paginate("/contacts", search="silva"):
      print(contact["id"], contact["name"])
  ```

  ```php PHP theme={null}
  function paginate(string $path, array $params = []): iterable
  {
      $page = 1;

      while (true) {
          $query = http_build_query($params + ['page' => $page, 'perPage' => 100]);
          $ch = curl_init(getenv('CONNECTA_URL') . $path . '?' . $query);
          curl_setopt_array($ch, [
              CURLOPT_RETURNTRANSFER => true,
              CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('CONNECTA_TOKEN')],
          ]);

          $body = json_decode(curl_exec($ch), true);
          yield from $body['data'];

          if (!$body['meta']['hasMore']) {
              return;
          }
          $page++;
      }
  }
  ```
</CodeGroup>

<Warning>
  A full sweep uses one request per page, and each one counts toward the
  [per-minute limit](/en/essentials/limites-de-uso). With `perPage=100`, you spend 1 request for
  every 100 records. Before increasing how often the loop runs, raise `perPage`.
</Warning>

## Watch out for data that changes

Each page is calculated at the moment of the request, based on the position of the records
(`page` × `perPage`). If records are created or removed between one page and the next, an item
may show up twice or be left out of the sweep.

For exports that need to be exact:

* Use a fixed date range when the endpoint accepts a period filter.
* Remove duplicates by `id` when combining the results.
* Run the sweep at a quieter time of day.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.