Постраничная выдача

Как перебрать список целиком и ничего не потерять.

Курсор, а не номер страницы

Все списки отдаются курсором. Запрос принимает два параметра:

ПараметрЗначение
limitСколько записей вернуть: от 1 до 100, по умолчанию 50
starting_afterКурсор из предыдущего ответа

Ответ всегда одной формы:

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

Пока has_more равно true, передавайте next_cursor в starting_after и запрашивайте дальше. Когда список закончился, has_more равно false, а next_cursor равен null.

cursor=""
while :; do
  page=$(curl -sG "https://api.tygy.ru/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

Почему не номера страниц

Номер страницы ломается, когда данные меняются во время перебора: новая запись сдвигает всё вниз, и одна запись приезжает дважды, а другая теряется. Курсор указывает на конкретную позицию, поэтому такого не происходит.

По той же причине мы не возвращаем общее количество. Точное число в живом списке устаревает в момент ответа, а его подсчёт стоит дороже самой страницы. Не полагайтесь на счётчики — перебирайте, пока has_more не станет false.

Порядок

Списки отсортированы от свежих к старым: по времени последнего изменения. Сообщения внутри диалога — наоборот, от старых к новым, это естественный порядок чтения переписки; параметр order=desc переворачивает его.

Только изменившееся

У списков есть параметр updated_since. Он принимает момент времени и возвращает только то, что менялось после него:

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

Так строится регулярная синхронизация: запомните время начала запроса, переберите страницы, в следующий раз спросите изменения с этого момента. Но если вам нужна быстрая реакция, лучше подписаться на вебхуки — они приходят сразу, а не по таймеру.

Испорченный курсор

Курсор непрозрачен: не разбирайте его и не собирайте руками. Если передать что-то своё, ответ будет 422:

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