Genesys Analytics API: Cursor vs Page for /api/v2/analytics/conversations/details/query

Getting inconsistent results when pulling conversation details. I’m trying to iterate through all calls from last week using POST /api/v2/analytics/conversations/details/query.

{
 "groupBy": [],
 "filter": [
 {
 "type": "equals",
 "field": "wrapupcode",
 "value": "Closed"
 }
 ],
 "interval": "2023-10-01T00:00:00.000Z/2023-10-08T00:00:00.000Z",
 "page": 1,
 "pageSize": 100
}

The docs mention cursor for pagination but the response doesn’t always include a nextPageToken. Sometimes it’s null even when I have more than 100 records. If I switch to using page and pageSize, it works fine but feels slow. Is cursor only for specific query types? I’ve seen posts saying cursor is the new standard but it’s broken for basic detail queries. Just want to know the reliable way to get all records without missing data or hitting rate limits. The nextPageToken behavior is confusing as hell.

Drop page and pageSize entirely. Those are for standard list endpoints, not analytics queries. The analytics API uses a cursor-based pagination model because the dataset is usually massive. If you stick with page numbers, you’ll hit rate limits or get truncated data without realizing it.

Here’s how the payload should look to actually get the next batch:

{
 "groupBy": [],
 "filter": [
 {
 "type": "equals",
 "field": "wrapupcode",
 "value": "Closed"
 }
 ],
 "interval": "2023-10-01T00:00:00.000Z/2023-10-08T00:00:00.000Z",
 "size": 100,
 "nextPageCursor": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..."
}

Notice the size field instead of pageSize. That’s the max number of records per cursor chunk. On the first request, leave nextPageCursor out or set it to null. The response body will contain a nextPageCursor string if there’s more data. You feed that string back into the next request’s nextPageCursor field. Keep looping until that field comes back empty or null.

One thing to watch out for: the cursor is time-sensitive. Don’t save it for later use. If you’re building this in Python using the genesyscloud SDK, the conversation_details_query_post method handles the cursor logic if you use the paginator helper, but doing it manually gives you more control over retries. Just make sure your OAuth token has analytics:conversation:view scope, otherwise you’ll get 403s that look like permission errors on the data itself.

Also, keep an eye on the interval. If you query too wide a range, the backend might time out. Splitting it into smaller chunks helps.

Cursor is definitely the right call for analytics. Just make sure you’re capturing the nextPageToken from the response headers and passing it back in the next request body, otherwise you’ll just loop the first 1000 records forever.