# Pagination

> List endpoints use cursor pagination with limit, after and before, and return {object, has_more, data}, newest first.

Source: https://docs.pidgely.com/pagination/

Every list endpoint (`GET /emails`, `GET /domains`, `GET /contacts`, …) returns the same envelope:

```json
{
  "object": "list",
  "has_more": true,
  "data": [
    { "id": "0199d8a2-7a10-7d02-8b4e-51c2a9f0e7b3", "…": "…" },
    { "id": "0199d8a2-6f3c-7c51-9e2a-3b1f0c6d4e21", "…": "…" }
  ]
}
```

Items are always ordered **newest first**. Ids are time-ordered (UUIDv7), so a cursor is simply the id of an item.

## Parameters

| Parameter | Description |
|---|---|
| `limit` | Page size, from 1 to 100. Outside that range: `422 validation_error` (`The pagination limit must be a number between 1 and 100.`) |
| `after` | Id of the **last** item of the previous page. Returns the next, older items. |
| `before` | Id of the **first** item of the current page. Returns the previous, newer items. |

`after` and `before` can't be combined (`You can only use either after or before, not both.`), and must be valid ids.

When you omit `limit`, `GET /emails` and `GET /templates` return 20 items; the other lists return up to 1,000 items in one page. `has_more` tells you whether there is another page in the direction you are reading.

## Iterating over everything

```js tab="Node.js"
import { Pidgely } from 'pidgely';

const pidgely = new Pidgely(process.env.PIDGELY_API_KEY);

let after;
do {
  const { data: page, error } = await pidgely.contacts.list({ limit: 100, after });
  if (error) throw new Error(error.message);
  for (const contact of page.data) console.log(contact.email);
  after = page.has_more ? page.data.at(-1).id : undefined;
} while (after);
```

```python tab="Python"
import os
import pidgely

pidgely.api_key = os.environ["PIDGELY_API_KEY"]

after = None
while True:
    page = pidgely.Contacts.list({"limit": 100, **({"after": after} if after else {})})
    for contact in page["data"]:
        print(contact["email"])
    if not page["has_more"]:
        break
    after = page["data"][-1]["id"]
```

```bash tab="cURL"
curl "https://api.pidgely.com/contacts?limit=100" -H "Authorization: Bearer $PIDGELY_API_KEY"
# then, with the id of the last item:
curl "https://api.pidgely.com/contacts?limit=100&after=0199d7f4-5d7b-7a2c-b4e1-9f3c2a6d8e05" -H "Authorization: Bearer $PIDGELY_API_KEY"
```

## Consistency

List endpoints may be served by a read replica and lag a moment behind writes. Retrieving a single object (for example `GET /emails/{id}`) always reads the primary database, so an email is visible right after you send it.
