# Pagination

> Page through list endpoints with the page and limit query parameters.

<!-- Source: https://docs.actuallycare.com/api/pagination -->

Every list endpoint takes the same two query parameters — `page` and `limit` — and returns the records under `data`, keyed by the resource name, with pagination metadata at `data.meta`:

```bash
curl "https://api.actuallycare.com/v1/clients?page=2&limit=50" \
  -H "X-API-Key: YOUR_API_KEY"
```

```json
{
  "success": true,
  "data": {
    "clients": [
      { "id": "7b1e9c44-2f6a-4d83-9c0e-5a1f2b3c4d5e" }
    ],
    "meta": { "page": 2, "limit": 50, "total": 137, "totalPages": 3, "hasMore": true }
  },
  "timestamp": "2026-06-11T18:24:09.123Z"
}
```

The entity key matches the resource — `data.clients` here, `data.leads` on `/v1/leads`, `data.listings` on `/v1/listings`, `data.appointments` on `/v1/appointments`. (Records trimmed for brevity — each entry is a full object; the per-endpoint field lists are in the [API reference](/api/reference).)

## Parameters

| Parameter | Type | Default | Notes |
| --- | --- | --- | --- |
| `page` | integer | `1` | Which page to fetch, starting at 1 |
| `limit` | integer | `25` | Records per page, maximum 100 |

Stick to the parameters documented for each endpoint in the [API reference](/api/reference) — don't invent sort or filter parameters that aren't listed there.

## The meta object

| Field | Meaning |
| --- | --- |
| `page` | The page you got back |
| `limit` | Records per page for this response |
| `total` | Total matching records across all pages |
| `totalPages` | Total number of pages at this `limit` |
| `hasMore` | `true` while there are more pages to fetch |

You're done when `hasMore` is `false` — or, defensively, when a page comes back empty.

## Fetch every page

Both loops below request 100 records at a time (the maximum) and stop when `data.meta.hasMore` goes `false`.

JavaScript:

```javascript
async function fetchAll(path, entity) {
  const all = [];
  let page = 1;
  let hasMore = true;

  while (hasMore) {
    const res = await fetch(
      `https://api.actuallycare.com/v1${path}?page=${page}&limit=100`,
      { headers: { "X-API-Key": process.env.ACTUALLYCARE_API_KEY } }
    );
    if (!res.ok) throw new Error(`HTTP ${res.status}`);

    const body = await res.json();
    all.push(...body.data[entity]);
    hasMore = body.data.meta.hasMore;
    page += 1;
  }

  return all;
}

const clients = await fetchAll("/clients", "clients");
```

Python:

```python
import os
import requests

def fetch_all(path, entity):
    records = []
    page = 1
    has_more = True

    while has_more:
        res = requests.get(
            f"https://api.actuallycare.com/v1{path}",
            headers={"X-API-Key": os.environ["ACTUALLYCARE_API_KEY"]},
            params={"page": page, "limit": 100},
        )
        res.raise_for_status()

        body = res.json()
        records.extend(body["data"][entity])
        has_more = body["data"]["meta"]["hasMore"]
        page += 1

    return records

clients = fetch_all("/clients", "clients")
```

## Paginate less

The fastest page is the one you don't fetch:

- **Filter server-side where filters exist.** For example, `GET /v1/listings` accepts `status`, `minPrice`, and `maxPrice` — filtering there beats downloading everything and filtering in your code. Each endpoint's filters are in [the listings reference](/api/reference/listings).
- **Mind the rate limit.** Every page is one request against your [rate limit](/api/rate-limits), so a full export at `limit=100` costs a request per hundred records. Cache results you'll reuse.
- **Don't poll for changes.** If you're re-fetching everything on a schedule just to spot what changed, subscribe to [webhooks](/concepts/webhooks) instead and let ActuallyCare push the changes to you.
