Pagination

Endpoints that return more than one record are paginated with a cursor. The mechanism is the same across the Veridion APIs, so a client written once works everywhere.

Request parameters

ParameterTypeDefaultDescription
page_sizeinteger, 1 to 200100How many records to return per page.
cursorstring, up to 1024 charactersN/AThe next_cursor value from a previous response. Omit it on the first call.
max_resultsinteger, 1 to 10000N/AAn optional cap on the total number of records returned across all pages. Takes precedence over page_size.
📘

A cursor is bound to the request that produced it. Reuse it as is, and do not change the other parameters of the query while paging through it.

Response fields

FieldDescription
resultThe records in this page.
next_cursorThe cursor to send on the next request, or null when there is nothing further to retrieve.
has_moreWhether another request will retrieve more data.
result_countThe total number of records in the result set.

The one rule: stop when next_cursor is null

next_cursor tells you whether to keep going. has_more tells you whether to keep going immediately.

This distinction matters because not every result set is finished when you start reading it. Most endpoints query data that already exists, and for those the two fields always agree. Some endpoints begin returning records while the rest are still being produced, and for those the set can be temporarily drained without being complete. This behavior will be documented for each endpoint individually.

A client that terminates on next_cursor == null works correctly in both cases. A client that terminates on has_more == false will stop early against an endpoint that is still producing.

📘

has_more: true with a null cursor cannot occur

The combination is impossible by construction, so there is no ambiguous state to handle.


Paginating a complete result set

For most endpoints the full result set exists before the first response is sent. Paging is a simple loop, and has_more mirrors next_cursor.

cursor = null                                  // omit on the first call

loop:
    page = GET /<endpoint>?cursor=<cursor>&page_size=<n>
    consume(page.result)

    if page.next_cursor == null:
        break

    cursor = page.next_cursor

Paginating a result set that is still being produced

Some endpoints return records as they become available rather than waiting for the whole set. These responses carry an additional status field, and the result set can grow between your requests.

status is a display label. It describes what the producer is doing, and it never needs to drive control flow.

statushas_morenext_cursorWhat the client does
processingtruepresentFetch the next page immediately.
processingfalsepresentNothing available right now. Wait, then re-request with the same cursor.
completetruepresentFetch the next page immediately.
completefalsenullStop.

The second row is the state that does not exist for a complete result set: the producer is still working, and there is nothing to hand you yet. Send the same cursor again after a delay and later records will arrive under it.

cursor = null                                  // omit on the first call

loop:
    page = GET /<endpoint>?cursor=<cursor>&page_size=<n>
    consume(page.result)

    if page.next_cursor == null:               // done
        break

    cursor = page.next_cursor

    if page.has_more:                          // more available now
        continue
    else:                                      // drained, producer still running
        sleep(backoff)                         // re-request the same cursor
        continue

The cursor is used verbatim either way. The only difference between the two branches is whether you pause first.

👍

Write the loop once

The second loop is correct for every paginated endpoint, including those whose result sets are always complete. Against a complete set the else branch is simply never reached.

If you are integrating against more than one Veridion API, implementing this version once is less work than maintaining two.


Caps and totals

max_results must be sent on every request. The cap is not carried in the cursor. If you omit it when requesting a later page, the cap no longer applies and paging continues through the full result set.

has_more goes false once the cap is reached, even when further records exist.

result_count ignores the cap. It reports the size of the result set itself, so a response can read result_count: 500 with has_more: false when you asked for ten. That is correct: five hundred records exist, and you have retrieved as many as you requested.

For an endpoint that is still producing records, result_count reflects what is known at the time of the response and can increase while status is processing.