Pagination

How to page through list endpoints.

List response shapes differ by resource; do not assume every endpoint shares a cursor or a page-number parameter. The events timeline uses exclusive continuation ordered by (occurredAt, id) using PostgreSQL timestamp and UUID order.

Before you poll

Use an authorised Live key with events:read at api.kuahr.com. Test keys cannot read this unpartitioned timeline. Use the same API address for every integration; Test keys are refused on this unpartitioned timeline. Initialisation and end-to-end outcomes are covered in poll and reconcile events.

Cursor paging (events)

GET /v1/events returns an array. Start without a cursor. After successfully processing a non-empty page, persist the last event’s exact occurredAt and id together, then send them as since and afterId. Keep the same eventType filter throughout a traversal. An empty page leaves your cursor unchanged.

# First page
curl "https://api.kuahr.com/v1/events?limit=100" \
  -H "X-Api-Key: kua_live_your_key_here"

# Next page: use the exact occurredAt and id of the last processed event.
curl --get "https://api.kuahr.com/v1/events" \
  --data-urlencode 'limit=100' \
  --data-urlencode 'since=2026-11-01T12:00:00.123456+00:00' \
  --data-urlencode 'afterId=80000000-0000-0000-0000-000000000000' \
  -H "X-Api-Key: kua_live_your_key_here"
let cursor: { since: string; afterId: string } | undefined;
for (;;) {
  const page = await kua.events.list({ ...cursor, limit: 100 });
  if (page.length === 0) break;
  for (const event of page) await handle(event);
  const last = page[page.length - 1];
  cursor = { since: last.occurredAt, afterId: last.id };
  await saveCursor(cursor);
}
cursor = {}
while True:
    page = kua.events.list(**cursor, limit=100)
    if not page:
        break
    for event in page:
        handle(event)
    last = page[-1]
    cursor = {"since": last.occurred_at, "after_id": last.id}
    save_cursor(cursor)

handle, saveCursor and save_cursor represent your processing and durable checkpoint storage. On restart, load that stored pair before continuing. Preserve the returned timestamp string, including fractional precision and offset; avoid rounding or parsing it through a lower-precision date type. URL-encode query parameters. Deduplicate event IDs when retrying a partially processed page.

Continuation and reconciliation

The paired cursor handles tied timestamps among already persisted events. It is not a database commit sequence or a consistent snapshot across requests. Events inserted or committed later with a tuple at or before a saved cursor can still be missed, including backdated imports, clock skew and transactions committed out of order. ID ordering within one timestamp matters too.

For reconciliation, periodically rescan an earlier timestamp or the complete retained timeline and deduplicate event IDs. A bounded overlap only mitigates late arrival: it cannot recover events older than its window. This continuation does not provide a blanket lossless guarantee or automatic webhook replay.

Search documentation

↑ ↓ to move · Enter to open · Esc to close