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

# Pagination

> Page numbers where an endpoint paginates at all. Several don't — and one uses message IDs instead.

Collection endpoints that paginate take one query parameter: `page`, an integer starting at `1`. That's the whole mechanism — no cursor token to store between requests, no opaque string to round-trip.

```bash theme={null}
curl "https://app.tied.com/api/v1/accounts/1/contacts?page=2" \
  -H "api_access_token: YOUR_TOKEN"
```

## What you get back differs by endpoint

Worth reading before you write one generic paginator and point it at everything, because the response shape isn't uniform.

<AccordionGroup>
  <Accordion title="Contacts — tells you the total" icon="users">
    `GET /api/v1/accounts/{account_id}/contacts` returns:

    ```json theme={null}
    {
      "meta": { "count": 143, "current_page": 1 },
      "payload": [ ]
    }
    ```

    `meta.count` is the total number of contacts matching the query, so you can compute how many pages exist. Default page size is 15.
  </Accordion>

  <Accordion title="Conversations — tells you counts, not a total" icon="messages-square">
    `GET /api/v1/accounts/{account_id}/conversations` returns:

    ```json theme={null}
    {
      "data": {
        "meta": {
          "mine_count": 4,
          "unassigned_count": 12,
          "assigned_count": 30,
          "all_count": 46
        },
        "payload": [ ]
      }
    }
    ```

    Notice what's missing: no `current_page`, no total for the query you actually ran. The numbers in `meta` are status-bucket counts — mine, unassigned, assigned, all — not a page count for whatever filters you passed. **The reliable end-of-list signal is an empty `payload` array**, not a count comparison.
  </Accordion>

  <Accordion title="Agents, teams, canned responses, custom filters — not paginated" icon="list">
    These return the full collection as a bare array, every time. No `page` parameter does anything, and there's no `meta` to read, because nothing is being paged — you get everything in one response. That's a reasonable design for what these lists actually are today (an account's agent roster, its teams, its canned responses). It stops being reasonable if you're building against an account with an unusually large canned-response library; there's no server-side limit protecting you from a large response body on these endpoints.
  </Accordion>
</AccordionGroup>

## The exception: message history

`GET /api/v1/accounts/{account_id}/conversations/{conversation_id}/messages` doesn't take a `page` parameter — passing one silently does nothing. Message history pages backward and forward from a message ID instead:

| Parameters | Result |
| - | - |
| *(none)* | The most recent 20 messages. |
| `before={message_id}` | Up to 20 messages older than that ID. |
| `after={message_id}` | Up to 100 messages newer than that ID. |
| `before` and `after` together | Up to 1000 messages between the two, oldest first. |

This isn't in the published parameter list for that endpoint, but it's the real, load-bearing behavior underneath both the Application API's conversation-scoped messages endpoint and the Client API's public messages endpoint. If you're walking a long conversation, page backward with `before` set to the oldest message ID you've seen, and stop when you get an empty array.

```bash theme={null}
curl "https://app.tied.com/api/v1/accounts/1/conversations/42/messages?before=8830" \
  -H "api_access_token: YOUR_TOKEN"
```

## Iterating safely

Whatever shape you're dealing with, the safe loop termination is the same: **stop when the page comes back empty**, not when you hit a count you precomputed at the start. Filters and totals can both change between your first request and your fifth.

```bash theme={null}
page=1
while :; do
  resp=$(curl -s "https://app.tied.com/api/v1/accounts/1/contacts?page=$page" \
    -H "api_access_token: YOUR_TOKEN")
  count=$(echo "$resp" | jq '.payload | length')
  [ "$count" -eq 0 ] && break
  echo "$resp" | jq '.payload'
  page=$((page + 1))
done
```

## Next

<CardGroup cols={2}>
  <Card title="Rate limits" icon="gauge" href="/api-reference/rate-limits">
    What happens if that loop runs faster than it should.
  </Card>

  <Card title="Errors" icon="circle-alert" href="/api-reference/errors">
    The shape of the body when a page request fails.
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.