---
title: "Pagination & sync"
url: https://docs.light-ai.app/pagination.md
canonical_url: https://docs.light-ai.app/pagination
last_updated: 2026-10-13
summary: "Cursor pagination, initial and incremental syncs with updated_since, and the gapless events feed."
api_status: beta
related:
  - https://docs.light-ai.app/webhooks
  - https://docs.light-ai.app/external-refs
  - https://docs.light-ai.app/api-reference/events/list-events
---

# Pagination & sync

> Cursor pagination, initial and incremental syncs with updated_since, and the gapless events feed.

List endpoints return `{ "data": [...], "has_more": true, "next_cursor": "…" }`. Pass `next_cursor` back as `cursor` until `has_more` is `false`. `limit` is 1–100 (default 25).

curl:

```bash
curl "https://api.light-ai.app/v1/leads?limit=100" \
  -H "Authorization: Bearer $LIGHT_AI_API_KEY"
```

JavaScript:

```javascript
const response = await fetch('https://api.light-ai.app/v1/leads?limit=100', {
  method: 'GET',
  headers: {
    Authorization: `Bearer ${process.env.LIGHT_AI_API_KEY}`,
  },
});
const data = await response.json();
```

Python:

```python
import os, requests

response = requests.get(
    "https://api.light-ai.app/v1/leads?limit=100",
    headers={
        "Authorization": f"Bearer {os.environ['LIGHT_AI_API_KEY']}",
    },
)
data = response.json()
```

## Initial sync

Page through leads, clients, projects and quotes with `sort=updated_asc`. Store the highest `updated_at` you saw (your high-water mark).

curl:

```bash
curl "https://api.light-ai.app/v1/clients?sort=updated_asc&limit=100" \
  -H "Authorization: Bearer $LIGHT_AI_API_KEY"
```

JavaScript:

```javascript
const response = await fetch('https://api.light-ai.app/v1/clients?sort=updated_asc&limit=100', {
  method: 'GET',
  headers: {
    Authorization: `Bearer ${process.env.LIGHT_AI_API_KEY}`,
  },
});
const data = await response.json();
```

Python:

```python
import os, requests

response = requests.get(
    "https://api.light-ai.app/v1/clients?sort=updated_asc&limit=100",
    headers={
        "Authorization": f"Bearer {os.environ['LIGHT_AI_API_KEY']}",
    },
)
data = response.json()
```

## Incremental sync

Poll with `sort=updated_asc&updated_since=<high-water mark minus 5 minutes>` and de-duplicate by `id` + `updated_at`: a write that commits late can carry an earlier timestamp.

## Gapless events feed

For a change feed that never misses anything, poll `GET /v1/events?sort=sync_asc`. Store `next_cursor` and pass it back as `cursor`: every event appears exactly once, even for slow transactions. Events are kept for 30 days. Filter with `type` or `types` (comma-separated).

curl:

```bash
curl "https://api.light-ai.app/v1/events?sort=sync_asc&types=lead.created,quote.approved&limit=100" \
  -H "Authorization: Bearer $LIGHT_AI_API_KEY"
```

JavaScript:

```javascript
const response = await fetch('https://api.light-ai.app/v1/events?sort=sync_asc&types=lead.created,quote.approved&limit=100', {
  method: 'GET',
  headers: {
    Authorization: `Bearer ${process.env.LIGHT_AI_API_KEY}`,
  },
});
const data = await response.json();
```

Python:

```python
import os, requests

response = requests.get(
    "https://api.light-ai.app/v1/events?sort=sync_asc&types=lead.created,quote.approved&limit=100",
    headers={
        "Authorization": f"Bearer {os.environ['LIGHT_AI_API_KEY']}",
    },
)
data = response.json()
```

## Webhooks or polling?

|  | Webhooks | Events feed |
| --- | --- | --- |
| Latency | Seconds | Your poll interval |
| Needs a public URL | Yes | No |
| Ordering | Not guaranteed | Exactly once, in commit order |
| Good for | Real-time CRM updates | Batch jobs, firewalled servers, catch-up after downtime |

History before you enabled the API is not replayed as events: read it with the list endpoints.
