---
title: "Pagination & sync"
description: "Lists page through an opaque cursor. Syncing works with updatedSince and includeDeleted, next to webhooks too."
lang: en
url: https://developers.bodo-app.com/en/guides/pagination/
apiVersion: 2026-11-01
---

# Pagination & sync

Lists page through an opaque cursor. Syncing works with updatedSince and includeDeleted, next to webhooks too.

## Paging

Ask for the next page with `nextCursor` as long as `hasMore` is true.

```http
GET /v1/contacts?limit=100&sort=-updatedAt

{
  "data": [ { "id": "con_4Nf7…", … }, … ],
  "hasMore": true,
  "nextCursor": "eyJ2IjoxLCJrIjoi…"
}

GET /v1/contacts?limit=100&sort=-updatedAt&cursor=eyJ2Ijox…
```

The SDKs walk the cursor themselves: `for await (const contact of bodo.contacts.list())` or `for contact in bodo.contacts.list()`.

## Rules

| Parameter | Rule |
| --- | --- |
| limit | default 25, at most 100 |
| cursor | bound to filters and sort order, otherwise [400 CURSOR_MISMATCH](/en/problems/CURSOR_MISMATCH/); expires after 24 h |
| sort | only values from the reference, such as `-updatedAt` |
| unknown | [400 UNKNOWN_PARAMETER](/en/problems/UNKNOWN_PARAMETER/), there is no filter language |
| total count | not in lists, use `GET /v1/contacts/count` (2 points) |

## Syncing, next to webhooks too

Remember the start time of every run and ask only for changes next time. Deletion markers come with `includeDeleted=true`. [Webhooks](/en/guides/webhooks/) only report that something changed; you fetch the state exactly like this. If a resource has no deletion markers, its reference says so.

```http
GET /v1/contacts?updatedSince=2026-11-03T09:00:00Z&includeDeleted=true&limit=100

{"data": [
  {"id": "con_4Nf7…", "lastName": "Mustermann", "updatedAt": "2026-11-03T09:14:22Z"},
  {"id": "con_9Qa2…", "deleted": true, "updatedAt": "2026-11-03T10:02:51Z"}
], "hasMore": false, "nextCursor": null}
```

> If your receiver is down for a while, catch up with `updatedSince`. You can also read events for 30 days through `GET /v1/events`.
