Pagination

How to walk a whole list without losing anything.

A cursor, not a page number

Every list is paginated by cursor. A request takes two parameters:

ParameterMeaning
limitHow many rows to return: 1 to 100, 50 by default
starting_afterThe cursor from the previous answer

The answer always has one shape:

{
  "data": [ … ],
  "has_more": true,
  "next_cursor": "eyJrIjoiMjAyNi0wOS0xMlQxMDowMDowMC4wMDBaIiwiaWQiOiJja3gxIn0"
}

While has_more is true, pass next_cursor as starting_after and ask again. When the list ends, has_more is false and next_cursor is null.

cursor=""
while :; do
  page=$(curl -sG "https://api.tg-desk.com/v1/contacts" \
    -H "Authorization: Bearer $TYGY_API_KEY" \
    --data-urlencode "limit=100" \
    ${cursor:+--data-urlencode "starting_after=$cursor"})
  echo "$page" | jq -c '.data[]'
  [ "$(echo "$page" | jq -r .has_more)" = "true" ] || break
  cursor=$(echo "$page" | jq -r .next_cursor)
done

Why not page numbers

Page numbers break when the data changes while you walk it: a new row shifts everything down, so one row arrives twice and another is skipped. A cursor points at a position, so that cannot happen.

For the same reason we do not return a total count. An exact number in a live list is stale the moment we send it, and computing it costs more than the page itself. Do not rely on counts — walk until has_more is false.

Order

Lists are newest-first, by last change. Messages inside a conversation are the opposite — oldest first, the natural reading order of a thread; order=desc flips it.

Only what changed

Lists accept updated_since. It takes an instant and returns only what changed after it:

curl -sG "https://api.tg-desk.com/v1/conversations" \
  -H "Authorization: Bearer $TYGY_API_KEY" \
  --data-urlencode "updated_since=2026-09-12T10:00:00Z"

That is how a periodic sync works: note the time you started, walk the pages, then next time ask for changes since that moment. If you need to react quickly, subscribe to webhooks instead — they arrive at once, not on a timer.

A broken cursor

The cursor is opaque: do not parse it or build one yourself. Passing something of your own answers 422:

{
  "error": {
    "code": "validation_failed",
    "details": [{ "field": "starting_after", "message": "Malformed cursor" }]
  }
}

Previous: Authentication and scopes

Next: Errors