Skip to main content
Grouped queries can use opaque, signed keyset cursors. A cursor is bound to the organization, catalog version, selected model members, filters, range, and ordering, including the requested limit. Array ordering is significant, including selected members, filters, and in values. Treat a cursor as an opaque string: do not decode, edit, or construct one. The rules are identical for agent_runs and agent_user_activity; each walk freezes rows against that model’s declared event clock. Only grouped queries ordered by dimensions paginate. A grouped query that sends no explicit order paginates too: the engine orders by every selected dimension ascending by default. When order is given, each of its terms must be a dimension for the query to paginate. Totals never paginate. Metric-ordered grouped queries are single-page top-N results and return cursor: null. Supplying a cursor to a totals query, or ordering by a metric while continuing a cursor walk, returns invalid_query.

Inclusion boundary and live measures

The first response contains an asOf instant. Send the same query fields with the returned cursor to continue the walk. asOf freezes which rows are included across every page, while measures remain live. A group whose rows change during a walk can therefore have a changed measure even though the set of included groups is stable.

Cursor invalidation

A cursor returns invalid_cursor when it is malformed, tampered with, replayed for another organization or query, or no longer matches the catalog version. Start a fresh query when this happens.

Two-page walk

The first request can use a small limit:
The first page contains the first two dimension groups and a non-null cursor. Send the same JSON with "cursor": "<cursor from page one>". The second page preserves the original asOf; continue until cursor is null. Do not change dimensions, metrics, filters, range, timezone, order, or limit between requests.