> ## Documentation Index
> Fetch the complete documentation index at: https://docs.propal.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Pagination

> Navigate through large collections with cursor-based pagination.

All list endpoints use **cursor-based pagination**. This is more reliable than offset-based pagination: insertions and deletions don't cause skipped or duplicated records.

## Request parameters

| Parameter | Type    | Default | Description                                                                      |
| --------- | ------- | ------- | -------------------------------------------------------------------------------- |
| `limit`   | integer | `25`    | Number of items to return. Min: `1`, max: `100`.                                 |
| `after`   | string  | —       | Cursor from a previous response. Fetch the next page starting after this cursor. |

## Response format

Every list endpoint returns the same pagination structure:

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "data": [
    { "id": "abc-123", "name": "Item 1" },
    { "id": "def-456", "name": "Item 2" }
  ],
  "pagination": {
    "has_more": true,
    "next_cursor": "ZGVmLTQ1Ng",
    "total_count": 142
  }
}
```

| Field         | Type           | Description                                                                                     |
| ------------- | -------------- | ----------------------------------------------------------------------------------------------- |
| `has_more`    | boolean        | `true` if there are more items after this page.                                                 |
| `next_cursor` | string \| null | Opaque cursor to pass as the `after` parameter for the next page. `null` when on the last page. |
| `total_count` | integer        | Total number of items matching your query (across all pages).                                   |

## Paginating through all results

<CodeGroup>
  ```javascript Node.js theme={"theme":{"light":"github-light","dark":"github-dark"}}
  async function fetchAllLeads(apiKey) {
    const leads = [];
    let cursor = undefined;

    while (true) {
      const url = new URL('https://api.propal.io/v1/leads');
      url.searchParams.set('limit', '100');
      if (cursor) url.searchParams.set('after', cursor);

      const response = await fetch(url, {
        headers: { 'Authorization': `Bearer ${apiKey}` },
      });
      const { data, pagination } = await response.json();

      leads.push(...data);

      if (!pagination.has_more) break;
      cursor = pagination.next_cursor;
    }

    return leads;
  }
  ```

  ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}}
  import requests

  def fetch_all_leads(api_key):
      leads = []
      cursor = None

      while True:
          params = {'limit': 100}
          if cursor:
              params['after'] = cursor

          response = requests.get(
              'https://api.propal.io/v1/leads',
              headers={'Authorization': f'Bearer {api_key}'},
              params=params,
          )
          body = response.json()

          leads.extend(body['data'])

          if not body['pagination']['has_more']:
              break
          cursor = body['pagination']['next_cursor']

      return leads
  ```

  ```bash cURL (page by page) theme={"theme":{"light":"github-light","dark":"github-dark"}}
  # First page
  curl "https://api.propal.io/v1/leads?limit=25" \
    -H "Authorization: Bearer pp_live_YOUR_KEY"

  # Next page (use next_cursor from previous response)
  curl "https://api.propal.io/v1/leads?limit=25&after=ZGVmLTQ1Ng" \
    -H "Authorization: Bearer pp_live_YOUR_KEY"
  ```
</CodeGroup>

## Filtering and sorting

List endpoints support filters via query parameters. Filters are combined with pagination:

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
# List only sent proposals, 50 per page
curl "https://api.propal.io/v1/proposals?status=approved&limit=50" \
  -H "Authorization: Bearer pp_live_YOUR_KEY"

# Search leads by name
curl "https://api.propal.io/v1/leads?search=acme&limit=10" \
  -H "Authorization: Bearer pp_live_YOUR_KEY"
```

Available filters vary per endpoint — check the specific resource documentation for details.

<Note>
  Cursors are opaque strings. Don't try to decode, modify, or construct them manually. Always use the `next_cursor` value returned by the API.
</Note>

## Best practices

* **Use the largest `limit` you need.** Fewer requests = fewer rate limit tokens consumed. Use `limit=100` for bulk operations.
* **Stop when `has_more` is `false`.** Don't make an extra request — the API tells you when you've reached the end.
* **Use `total_count` for progress.** Display progress bars or "showing X of Y" indicators using `total_count`.
