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

# How to Paginate CloudTalk API Collection Responses

> Core CloudTalk collection endpoints use page-based pagination with the page and limit query parameters. Dialer endpoints use cursor pagination instead.

Most core API list endpoints — call history, contacts, agents, tags and the rest — return resources in pages rather than all at once. You control page size with the `limit` parameter and navigate between pages with the `page` parameter. Their responses include four metadata fields that tell you how many total records match your query and how many pages remain, giving you what you need to walk through a large result set without guesswork.

<Note>
  **Pagination is per-endpoint, not universal.** [List countries](/api-reference/utilities/list-countries), for example, returns a plain array inside `responseData` and accepts no `page` or `limit`. Check whether the endpoint documents these parameters before building a paging loop around it.
</Note>

<Note>
  **Dialer endpoints paginate differently.** They are cursor-based: pass `limit` (`1`–`100`, default `50`) plus an opaque `cursor`, and read the next cursor from `meta.nextCursor` in the response. A `null` `nextCursor` means there are no more pages. The `page`, `pageCount` and `itemsCount` fields described below do not apply there.
</Note>

## Query Parameters

Append these parameters to any collection endpoint URL to control pagination behavior.

<ParamField query="limit" type="integer">
  Number of items to return per page. Must be between `1` and `1000`. Omit it and the server applies its own default, which it reports back in the envelope's `limit` field. Use larger values (100–500) for batch export jobs and smaller values when you only need the most recent records.
</ParamField>

<ParamField query="page" type="integer">
  Page number to retrieve, starting at `1`. Omit it to get the first page.
</ParamField>

***

## Response Envelope Fields

Paginated core API list endpoints wrap their payload in the standard `responseData` envelope. The following fields drive your iteration logic.

<ResponseField name="itemsCount" type="integer int64" required>
  Total number of resources matching your query across **all** pages. Use this to show record counts in your UI or to estimate job duration.
</ResponseField>

<ResponseField name="pageCount" type="integer int64" required>
  Total number of pages available for the current `limit`. When `pageNumber` equals `pageCount`, you have reached the last page.
</ResponseField>

<ResponseField name="pageNumber" type="integer int64" required>
  The page number included in this response (1-indexed). Mirrors the `page` query parameter you sent.
</ResponseField>

<ResponseField name="limit" type="integer int64" required>
  The maximum number of items per page as applied by the server. Mirrors the `limit` query parameter you sent, or the server default if you omitted it.
</ResponseField>

<ResponseField name="data" type="array" required>
  The resource objects for the current page. An empty array (`[]`) means no results matched your query.
</ResponseField>

***

## Iterating Through Pages

The simplest iteration strategy is to keep incrementing `page` until `pageNumber` equals `pageCount`. Drive your loop off `pageCount` rather than off what happens past the last page — that behaviour is not part of the documented contract.

<Steps>
  <Step title="Send your first request">
    Issue a request with `page=1` and your desired `limit`. Read `pageCount` from the response to know how many total requests you need.
  </Step>

  <Step title="Process the current page">
    Iterate over the `data` array and process each record — write to a database, transform for another API, queue for async work, etc.
  </Step>

  <Step title="Check for more pages">
    Compare `pageNumber` to `pageCount`. If `pageNumber < pageCount`, increment `page` by 1 and repeat from Step 1.
  </Step>

  <Step title="Stop when done">
    When `pageNumber === pageCount`, you have consumed all matching records. Treat an empty `data` array as a stop condition too, so a mid-run change in the result set cannot spin the loop.
  </Step>
</Steps>

***

## Examples

<CodeGroup>
  ```bash cURL — page 1 theme={"system"}
  curl -u KEY_ID:KEY_SECRET \
    -H "Accept: application/json" \
    'https://my.cloudtalk.io/api/calls/index.json?limit=100&page=1'
  ```

  ```bash cURL — page 2 theme={"system"}
  curl -u KEY_ID:KEY_SECRET \
    -H "Accept: application/json" \
    'https://my.cloudtalk.io/api/calls/index.json?limit=100&page=2'
  ```
</CodeGroup>

The following Python example fetches every page of calls within a date range and collects all records into a single list.

```python Python — fetch all pages theme={"system"}
import requests

BASE_URL = "https://my.cloudtalk.io/api/calls/index.json"
KEY_ID = "your_key_id"
KEY_SECRET = "your_key_secret"

def fetch_all_calls(date_from: str, date_to: str, limit: int = 100) -> list:
    """Fetch every page of calls between date_from and date_to."""
    all_calls = []
    page = 1

    while True:
        params = {
            "limit": limit,
            "page": page,
            "date_from": date_from,
            "date_to": date_to,
        }
        response = requests.get(
            BASE_URL,
            auth=(KEY_ID, KEY_SECRET),
            headers={"Accept": "application/json"},
            params=params,
        )
        response.raise_for_status()

        envelope = response.json()["responseData"]
        all_calls.extend(envelope["data"])

        print(
            f"Fetched page {envelope['pageNumber']} of {envelope['pageCount']} "
            f"({len(envelope['data'])} records)"
        )

        # Stop when we have retrieved the final page
        if envelope["pageNumber"] >= envelope["pageCount"]:
            break

        page += 1

    print(f"Total records retrieved: {len(all_calls)} of {envelope['itemsCount']}")
    return all_calls


calls = fetch_all_calls("2024-01-01 00:00:00", "2024-01-31 23:59:59")
```

***

## Best Practices

<Tip>
  Use a `limit` between **100 and 500** for background batch jobs. This balances response latency, memory consumption, and the number of round-trips required to export large datasets.
</Tip>

* **Filter before you paginate.** [Call history](/api-reference/calls/call-history) accepts `date_from`, `date_to`, `contact_id`, `user_id`, `type`, `status`, `tag_id` and `call_id`; [List contacts](/api-reference/contacts/list-contacts) accepts `country_id`, `tag_id`, `industry` and `keyword`. Filters differ per endpoint — a tight filter dramatically reduces `itemsCount` and the number of pages you walk through.
* **Don't rely on absolute page offsets for real-time data.** If new records are created between page requests, a record may appear on two consecutive pages or be skipped. For near-real-time sync, re-query with a narrow `date_from` / `date_to` window on endpoints that support it, rather than resuming from a page number.
* **Handle empty pages gracefully.** If `data` is an empty array, stop iterating rather than retrying.
* **Respect rate limits.** Tight pagination loops can exhaust your 60 requests-per-minute budget quickly. Add a short sleep between pages or use the largest `limit` your use case allows. See the [Rate Limiting guide](/guides/rate-limiting) for details.

***

## Conversation Intelligence Pagination

<Warning>
  Conversation Intelligence is **not** a paginated collection of calls. There is no endpoint that lists CI calls. Every CI endpoint takes a single call ID — `/ai/calls/{callId}/summary`, `/overall-sentiment`, `/talk-listen-ratio`, `/topics`, `/transcription`, `/smart-notes`, `/details-link` — and returns data for that one call.
</Warning>

Two of those endpoints paginate, and they paginate **within** a call: [Topics](/api-reference/conversation-intelligence/topics) and [Transcription](/api-reference/conversation-intelligence/transcription). Both use **offset/limit** rather than the page-based scheme above, and neither uses the `responseData` envelope.

<ParamField query="limit" type="integer">
  Maximum number of records to return in a single response. Minimum `1`.
</ParamField>

<ParamField query="offset" type="integer" default="0">
  Number of records to skip before returning results. To move to the next page, add `limit` to the previous `offset`.
</ParamField>

The payload sits under a top-level `data` object, with a sibling `pagination` object carrying `limit`, `offset` and `total`:

```json Transcription response (abridged) theme={"system"}
{
  "data": {
    "callId": 12345,
    "segments": [
      { "start": 1.501, "end": 4.599, "caller": "caller2", "text": "Hello, I would like to ask for help." },
      { "start": 5.173, "end": 8.599, "caller": "caller1", "text": "Hi. What's your issue?" }
    ],
    "callers": [
      { "id": 5000, "type": "contact", "localIdentifier": "caller1" },
      { "id": 1000, "type": "agent", "localIdentifier": "caller2" }
    ],
    "language": "en"
  },
  "pagination": { "limit": 2, "offset": 0, "total": 10 }
}
```

To read a full transcription, keep incrementing `offset` by `limit` until `offset >= pagination.total`. The segments accumulate; `data.callId`, `data.callers` and `data.language` repeat on every page.

```python Python — fetch a complete transcription theme={"system"}
import requests

CI_BASE = "https://api.cloudtalk.io/v1"
KEY_ID = "your_key_id"
KEY_SECRET = "your_key_secret"


def fetch_transcription(call_id: int, limit: int = 50) -> list:
    """Fetch every transcription segment for a single call."""
    segments = []
    offset = 0

    while True:
        response = requests.get(
            f"{CI_BASE}/ai/calls/{call_id}/transcription",
            auth=(KEY_ID, KEY_SECRET),
            headers={"Accept": "application/json"},
            params={"limit": limit, "offset": offset},
        )
        response.raise_for_status()
        body = response.json()

        segments.extend(body["data"]["segments"])

        offset += limit
        if offset >= body["pagination"]["total"]:
            break

    return segments


for segment in fetch_transcription(12345):
    print(f"[{segment['start']:.1f}s] {segment['caller']}: {segment['text']}")
```

<Tip>
  To work across many calls, page through [Call history](/api-reference/calls/call-history) on the core API first, then request Conversation Intelligence per call ID from that list.
</Tip>


## Related topics

- [CloudTalk API Response Envelope Formats and Schema](/guides/response-envelopes.md)
- [How to Authenticate Requests to the CloudTalk REST API](/guides/authentication.md)
- [CloudTalk REST API v1.7 — Complete Developer Reference](/api-reference/overview.md)
