# Pagination

Page through list endpoints with limit and offset, and use has_more to tell when you've reached the last page.

Every list endpoint pages the same way. You ask for a page with `limit` and `offset`, and the response says how many items there are in total and whether another page follows.

## Request parameters

| Parameter | Meaning |
| - | - |
| `limit` | How many items to return. Each endpoint has its own default and maximum, listed below. |
| `offset` | How many items to skip before this page. Defaults to `0`. |

A `limit` outside the endpoint's range, or a negative `offset`, answers `400 VALIDATION_ERROR`.

## Response fields

The items are under a key named for the resource, such as `leads` or `deals`. Alongside them, every list response carries:

| Field | Meaning |
| - | - |
| `count` | Items in this page. |
| `total` | Items matching the request, across all pages. |
| `limit` | The page size that was applied. |
| `offset` | Items skipped before this page. |
| `has_more` | `true` when another page follows. |

## Page through a list

Request pages until `has_more` is `false`, advancing `offset` by `count` each time:

**Node.js**

```javascript
async function listAllLeads() {
  const leads = [];
  let offset = 0;
  while (true) {
    const url = new URL("https://api.versionseven.ai/v1/leads");
    url.searchParams.set("limit", "100");
    url.searchParams.set("offset", String(offset));

    const response = await fetch(url, {
      headers: { Authorization: `Bearer ${process.env.VICTORIA_API_KEY}` },
    });
    if (!response.ok) throw new Error(`Request failed with status ${response.status}`);

    const page = await response.json();
    leads.push(...page.leads);
    if (!page.has_more) return leads;
    offset += page.count;
  }
}
```

**Python**

```python
import os

import requests


def list_all_leads():
    leads = []
    offset = 0
    while True:
        response = requests.get(
            "https://api.versionseven.ai/v1/leads",
            headers={"Authorization": f"Bearer {os.environ['VICTORIA_API_KEY']}"},
            params={"limit": 100, "offset": offset},
        )
        response.raise_for_status()
        page = response.json()
        leads.extend(page["leads"])
        if not page["has_more"]:
            return leads
        offset += page["count"]
```

## Limits by endpoint

| Endpoint | Items key | Default limit | Maximum limit |
| - | - | - | - |
| [`GET /v1/accounts`](https://docs.versionseven.ai/api-reference/accounts/list-accounts) | `accounts` | 500 | 500 |
| [`GET /v1/leads`](https://docs.versionseven.ai/api-reference/leads/list-leads) | `leads` | 20 | 100 |
| [`GET /v1/campaigns`](https://docs.versionseven.ai/api-reference/campaigns/list-campaigns) | `campaigns` | 500 | 500 |
| [`GET /v1/campaigns/{campaign_id}/webhooks`](https://docs.versionseven.ai/api-reference/campaigns/list-webhooks) | `webhooks` | 100 | 500 |
| [`GET /v1/crm/pipelines`](https://docs.versionseven.ai/api-reference/crm-pipelines/list-pipelines) | `pipelines` | 100 | 500 |
| [`GET /v1/crm/deals`](https://docs.versionseven.ai/api-reference/crm-deals/list-deals) | `deals` | 50 | 100 |

## Ordering

Results come back in a stable order, with ties broken by `id`, so paging never repeats or skips an item while the underlying data stays the same. Leads, campaigns and deals are listed newest first, so records created while you page push later pages along. If you need an exact snapshot of a large list, collect the IDs first and fetch details afterwards.

## `page` on the leads list

[`GET /v1/leads`](https://docs.versionseven.ai/api-reference/leads/list-leads) also accepts `page`, its original way of paging, and returns `page` in the response. Prefer `offset`, which works the same on every list endpoint. When a request sends both, `offset` wins.
