Skip to content

Pagination and syncing

Every list answers the same shape:

{
"data": [],
"pagination": { "total": 128, "limit": 20, "offset": 0, "hasMore": true }
}

limit defaults to 20 and caps at 100.

Without a sync parameter a list is ordered newest first (createdAt descending); with one it is ordered by updatedAt ascending. Every order carries the row id as a tiebreak, so no two rows ever compare equal.

Good for showing a page to a person:

Terminal window
curl -s "$TKANA_API/customers?limit=20&offset=40" -H "Authorization: Bearer $TKANA_KEY"

Rows move between pages while data changes, so offset paging is fine for a screen and wrong for a copy you intend to keep.

To hold a current copy, ask for what changed and follow the cursor.

  1. Start from your watermark.

    Terminal window
    curl -s "$TKANA_API/tickets?updatedAfter=2026-03-01T00:00:00Z" \
    -H "Authorization: Bearer $TKANA_KEY"
  2. Take pagination.nextCursor from the response and pass it back as cursor.

    Terminal window
    curl -s "$TKANA_API/tickets?cursor=eyJ1cGRhdGVkQXQiOi..." \
    -H "Authorization: Bearer $TKANA_KEY"
  3. Repeat while hasMore is true. Store the last nextCursor and resume from it next time — it stays valid once you are caught up.

A sync reports rows that were created, changed, or removed. A removal arrives in data in place of the row, in its own position in the same ordering, so one cursor carries both streams and there is nothing to reconcile separately:

{
"object": "removed",
"id": "8f14e45f-ceea-4c1a-9b31-9f3ba3a5d9c1",
"resource": "ticket",
"removedAt": "2026-05-04T09:12:33.019Z"
}

Branch on object === "removed" before reading any other field. No published resource carries that field, so the two shapes can never be confused — and a client that checks it first needs no other change when a future resource starts reporting removals too.

Three things worth knowing:

  • Only a sync contains them. An ordinary list — no updatedAfter, no cursor — returns what exists, and never a removal.
  • A record is reported removed once. Removals recorded before your first sync are not replayed, so treat a removal for something you do not hold as a no-op.
  • Deleting a customer removes their tickets too. Both removals are reported, each on its own resource’s sync, so an integration that syncs only tickets still hears about it.

If you would rather be told as it happens, subscribe to the customer.deleted and ticket.deleted webhooks — they carry the same record, with the same removedAt.