GaurGaur docs

Pagination

Page through contract results that don't fit in a single response, and read the response envelope correctly.

The REST query API returns results in pages. Every successful response uses the same envelope.

The response envelope

{
  "data": {
    "pagination": {
      "items": [
        { "store_name": "Downtown", "revenue_usd": 84210.50 },
        { "store_name": "Midtown",  "revenue_usd": 91040.25 }
      ],
      "total_items":     248,
      "page":            1,
      "limit":           100,
      "total_pages":     3,
      "has_next_page":   true,
      "has_prev_page":   false
    },
    "execution_time_ms": 53
  },
  "message": null
}

The rows live at data.pagination.items, not at the top of data. Reading data.items or data.rows will return undefined; clients that assume rows live higher up than they do are a common cause of "the query returned nothing" bugs that aren't actually empty.

FieldMeaning
data.pagination.itemsThe rows for the current page.
data.pagination.total_itemsTotal rows across all pages.
data.pagination.pageCurrent page number, starting at 1.
data.pagination.limitPage size actually applied (may differ from requested).
data.pagination.total_pagesTotal number of pages.
data.pagination.has_next_pageWhether a page after this one exists.
data.pagination.has_prev_pageWhether a page before this one exists.
data.execution_time_msQuery execution time in milliseconds.
messageInformational message, usually null.

The 10,000-row maximum

Every query response is capped at 10,000 rows per page. If you ask for more, the request succeeds but the response silently clamps to 10,000; pagination.limit will reflect the effective value, not what you requested.

// Request
{ "query": { "limit": 1000000 } }

// Response (success, but clamped)
{ "data": { "pagination": { "limit": 10000, ... } } }

This is the single most-important behavior to know if you're processing a large result set. Always read pagination.limit from the response and trust it over what you sent, and always check has_next_page to decide whether to keep paging. Code that assumes "I asked for a million rows so I have them all" will see exactly 10,000 rows and miss the rest.

Requesting a page

Control paging with limit and offset in the query:

  • limit: requested page size (clamped to 10,000).
  • offset: how many rows to skip.

For page n, use offset = (n - 1) * limit. Total page count is total_pages = ceil(total_items / limit).

{
  "contract_name": "store_performance",
  "query": {
    "measures": ["revenue_usd"],
    "dimensions": [{ "name": "store_name" }],
    "sorts": [{ "field": "revenue_usd", "direction": "desc" }],
    "limit": 100,
    "offset": 0
  }
}

A two-call example

You want all 248 stores' revenue, sorted desc, in pages of 100.

Call 1:

{
  "contract_name": "store_performance",
  "query": {
    "measures": ["revenue_usd"],
    "dimensions": [{ "name": "store_name" }],
    "sorts": [{ "field": "revenue_usd", "direction": "desc" }],
    "limit": 100,
    "offset": 0
  }
}

Response:

{
  "data": {
    "pagination": {
      "items": [ /* 100 rows */ ],
      "total_items":     248,
      "page":            1,
      "limit":           100,
      "total_pages":     3,
      "has_next_page":   true,
      "has_prev_page":   false
    },
    "execution_time_ms": 53
  }
}

Call 2: offset = 100, same limit.

{
  "contract_name": "store_performance",
  "query": {
    "measures": ["revenue_usd"],
    "dimensions": [{ "name": "store_name" }],
    "sorts": [{ "field": "revenue_usd", "direction": "desc" }],
    "limit": 100,
    "offset": 100
  }
}

Response: another 100 rows, page: 2, has_next_page: true. One more call with offset: 200 finishes the result set.

Paging loop

To consume a whole result set programmatically:

offset = 0
limit  = 100   # or whatever, will be capped at 10000
loop:
  response = query(limit, offset)
  process(response.data.pagination.items)
  if not response.data.pagination.has_next_page: stop
  offset = offset + response.data.pagination.limit

Two things to note: increment offset by the effective limit from the response, not your requested limit, in case the request was clamped. And stop on has_next_page == false, not on item count, in case the last page is partial.

Sort stability across pages

sorts is required for stable paging. Without an explicit sort, the order of items can shift between calls and pagination will skip or duplicate rows. Always specify at least one sort field, and pick one whose values are unique (a primary-key dimension is safest) so two rows never tie.

Next

On this page