Pagination
Pagination style varies by API and version:
| API | Style | Collection key | Next page |
|---|---|---|---|
| Contracting & Hierarchies API v2 | Token | items | page.nextToken → page_token param |
| Identity API (v2) | Token | items | page.nextToken → page_token param |
| ProducerSync API v2 | Continuation token | embedded | links.next.href |
v2 Token Pagination — Contracting, Hierarchies & Identity
All v2 list endpoints share one envelope: results in a top-level items array, pagination metadata in page.
{
"items": [ { ... }, { ... } ],
"page": {
"size": 25,
"nextToken": "eyJ2IjoxLCJrIjp7Li4ufX0"
}
}
| Field | Description |
|---|---|
items | The page of results. Empty array when nothing matches. |
page.size | Number of items actually returned in this response — equal to items.length, so an empty result reports 0. |
page.nextToken | Opaque token for the next page, or null on the last page. The token format is server-controlled — never parse or construct it. |
Query parameters:
| Parameter | Description |
|---|---|
page_token | The previous response's page.nextToken. Omit on the first request. |
page_size | Requested items per page. Defaults to 25 on all v2 endpoints. |
The request parameter and the response field have different names. You read the token out of
page.nextTokenand send it back aspage_token— there is nonextTokenquery parameter. Response bodies arecamelCase; query parameters arelower_snake_case. See Data Formats and Field Types.
Page size limits: page_size must be between 1 and 250 on Contracting, Hierarchies and Identity alike. Out-of-range values are rejected with a 400 rather than clamped, so you get an explicit error instead of a silently truncated page.
Read page.size back off the response rather than assuming it equals what you asked for: page.size is the number of items actually returned, so it is smaller than your requested size on the last page and 0 on an empty result.
Walking from the first page to the second:
# First request — no token.
curl -H "Authorization: Bearer $ACCESS_TOKEN" \
"https://api.sandbox.agentsync.io/contracting/v2/producers?page_size=25"
{
"items": [ { ... } ],
"page": {
"size": 25,
"nextToken": "eyJ2IjoxLCJrIjp7ImlkIjoiMDBiNjc5NWUtYmNmNS0xNDZhLWEzMGYtYmI4NTk0MzBhMTk5In19"
}
}
# Second request — the value of page.nextToken, sent as page_token.
curl -H "Authorization: Bearer $ACCESS_TOKEN" \
"https://api.sandbox.agentsync.io/contracting/v2/producers?page_size=25&page_token=eyJ2IjoxLCJrIjp7ImlkIjoiMDBiNjc5NWUtYmNmNS0xNDZhLWEzMGYtYmI4NTk0MzBhMTk5In19"
Keep page_size (and any filters) identical across every request in a run. Repeat until page.nextToken is null.
Troubleshooting: the same page keeps coming back
Check the parameter name first. Only page_token advances the page — nextToken, next_token, and pageToken are all ignored, and unrecognized parameters are dropped rather than rejected. So the wrong name returns 200 with the first page every time, not an error.
A 400 actually tells you the opposite: the name was right and the token couldn't be decoded. Send the token back exactly as received — it is opaque and URL-safe, so it needs no encoding, trimming, or base64 decoding.
Iterating all pages (Python):
def paginate_v2(access_token, base_url, path, params=None):
"""Fetch every item from a v2 token-paginated list endpoint."""
items = []
params = dict(params or {})
while True:
response = requests.get(
f"{base_url}{path}",
headers={"Authorization": f"Bearer {access_token}"},
params=params,
)
response.raise_for_status()
data = response.json()
items.extend(data["items"])
next_token = data["page"]["nextToken"]
if next_token is None:
return items
params["page_token"] = next_token
No totals by design. v2 responses do not include
totalElementsortotalPages— iterate untilnextTokenisnull. A pagination run is not a point-in-time snapshot: records updated mid-run may first appear on a later poll.
ProducerSync API v2 — Continuation Token Pagination
ProducerSync v2 endpoints paginate with continuation tokens carried in a links object.
First Page
Your initial request returns:
- a set of results under the
embeddedkey - a
linksobject, including anextURL for retrieving the next page
Note: The ProducerSync API uses
embeddedandlinks, which differs from theitemsenvelope used by Contracting, Hierarchies, and Identity. If you integrate multiple APIs, handle each collection key separately.
Example Response:
{
"embedded": {
"licenses": [
{ ... },
{ ... }
]
},
"links": {
"self": {
"href": "https://api.agentsync.io/v2/licenses?continuationToken=0"
},
"next": {
"href": "https://api.agentsync.io/v2/licenses?continuationToken=11862929"
}
}
}
Iterating with links.next
Follow the URL in links.next.href until the end of the dataset:
GET https://api.agentsync.io/v2/licenses?continuationToken=11862929
End of Results
On the final page:
- the response will NOT include an
embeddedobject links.next.hrefwill includecontinuationToken=0
{
"links": {
"self": {
"href": "https://api.agentsync.io/v2/licenses?continuationToken=11862929"
},
"next": {
"href": "https://api.agentsync.io/v2/licenses?continuationToken=0"
}
}
}
A query with no results at all returns the same shape — no embedded key and continuationToken=0 on both links. Handle this case gracefully.
Controlling Page Size
Pass size to control results per page (default 250):
- Minimum: 1
- Maximum: 1000
GET /v2/licenses?size=500