Skip to content

Pagination and sync

Lists are paged with an opaque cursor, and the same ordering that pages a register is the one that syncs it.

Walking a list

Ask for a page. If has_more is true, pass next_cursor back.

curl "https://your-workspace.kitset.io/api/v1/assets?limit=100" \
  -H "Authorization: Bearer $KITSET_KEY"
import httpx

def walk(client, path):
    cursor = None
    while True:
        params = {"limit": 500}
        if cursor:
            params["cursor"] = cursor
        page = client.get(path, params=params).raise_for_status().json()
        yield from page["data"]
        if not page["has_more"]:
            return
        cursor = page["next_cursor"]

limit defaults to 100 and may go to 1000.

What the cursor is

A signed position in the result, not a page number. Three consequences worth knowing:

  • Keep the filters identical between pages. The cursor records the filters it was issued under, and a request that changes them is refused rather than silently walking rows the first filter excluded.
  • Do not edit it. An altered cursor is refused. It is not a base64 offset you can increment.
  • A cursor is not a bookmark. Use it to finish a walk, not to resume one tomorrow. For that, use updated_since.

There is no total. Counting would mean a second pass over the whole filtered set on every page, and the number would be stale before you read it. has_more is what a walk actually needs.

Keeping a mirror current

Every record carries updated_at, and every list can be filtered on it.

curl "https://your-workspace.kitset.io/api/v1/assets?updated_since=2026-09-19T00:00:00Z" \
  -H "Authorization: Bearer $KITSET_KEY"

The pattern that works:

  1. Walk the full register once and record the highest updated_at you saw.
  2. On each later run, pass that value as updated_since and walk again.
  3. Move your watermark forward only when the walk finishes.

Overlap deliberately. Subtract a few minutes from your watermark before sending it. Records are stamped when they are written rather than when the transaction commits, so a long write can commit a row stamped slightly earlier than one you have already seen. Re-reading a handful of rows costs nothing; missing one is silent and permanent, because the next edit moves that row past the window you missed it in.

Deletions are not visible to a poll. A record removed from kitset stops appearing in the list, and nothing tells you which one went. If your mirror must notice deletions, reconcile ids on a full walk periodically rather than relying on the delta.

Filters

Each endpoint accepts the filters named in the reference, plus search where the register supports it. A filter value outside the set an endpoint accepts is an error rather than an empty page — an empty page and "nothing matched" are indistinguishable, and a mirror that reads one as the other deactivates every record it holds.