Paging
List methods return results a page at a time.
The Legacy APIs page differently and hand back a complete next-page URL instead of a cursor. See Legacy API conventions.
Paging is expressed as fields on the request and response messages. You send a page size and, after the first call, a cursor. Most services use the shared pagingOptions and pagingMetadata pair:
| Direction | Field | Meaning |
|---|---|---|
| Request | pagingOptions.pageSize | Maximum items to return. Omit for the service default |
| Request | pagingOptions.cursor | The nextCursor from the previous response. Omit for the first page |
| Response | pagingMetadata.nextCursor | Cursor to send on the next request |
| Response | pagingMetadata.hasMore | Whether more results exist |
| Response | pagingMetadata.totalResults | Total matching results, where the service supports it |
Every request must carry the full query
The cursor identifies your position in the result set. It does not remember your query.
Each request must repeat the same filters, search, and sortBy values you sent on the first call, alongside the new cursor. A request that sends only the cursor is a valid request for a different, unfiltered result set, and it will return 200 with the wrong rows rather than an error.
Walking through a result set
First call. No cursor, filters supplied:
curl -X POST 'https://demo.apigateway.co/grpc/v1/crm/company/list' \
--header 'Authorization: Bearer <access_token>' \
--header 'Content-Type: application/json' \
--data '{
"namespace": "AG-EXAMPLE",
"filtersV2": { "filterGroups": [ /* ... */ ] },
"pagingOptions": { "pageSize": 100 }
}'
The response carries the cursor for the next page:
{
"crmObjects": [ /* ... */ ],
"pagingMetadata": {
"hasMore": true,
"nextCursor": "eyJvZmZzZXQiOjEwMH0=",
"totalResults": "2140"
}
}
Second call. The same namespace and filtersV2, plus the cursor:
curl -X POST 'https://demo.apigateway.co/grpc/v1/crm/company/list' \
--header 'Authorization: Bearer <access_token>' \
--header 'Content-Type: application/json' \
--data '{
"namespace": "AG-EXAMPLE",
"filtersV2": { "filterGroups": [ /* ... */ ] },
"pagingOptions": { "pageSize": 100, "cursor": "eyJvZmZzZXQiOjEwMH0=" }
}'
Repeat while hasMore is true. Stop when it is false, not when a page comes back short.
Things to know
Field names and nesting vary by service. Most use pagingOptions and pagingMetadata, some nest paging differently, and some list methods are not paged at all. The method's page in the API reference is authoritative for the shape.
Page size is capped, and exceeding the cap is not an error. Ask for more than a service allows and you get the cap, silently. CRM defaults to 100 and caps at 1000.
Cursors are positional, so a mutating result set can shift under you. Records created or deleted between calls move the boundary, which can skip or repeat rows across pages. For an exact snapshot of a large, actively changing set, narrow the query with a filter on a stable field rather than relying on paging alone.
totalResults is optional. Services that do not support it return 0. Use hasMore to decide whether to keep going, never a page count derived from totalResults.
Paging moves forward only. There is no previous, first, or last cursor. To go back, re-walk from the start.
The two GET methods take paging as query parameters. GET /v1beta/widgets accepts pagingOptions.cursor and pagingOptions.pageSize in the query string rather than a body. The semantics above are unchanged.