Pagination behavior on /api/v2/analytics/conversations/details/query

Could someone explain the pagination mechanism for the analytics details query endpoint? I am building a Grafana data source plugin and need to aggregate full conversation datasets.

  1. Call /api/v2/analytics/conversations/details/query with size=100.
  2. Receive nextPageToken in the response header.
  3. Retry with the token.

The nextPageToken expires rapidly. Does this endpoint support offset-based pagination like other GC APIs, or must I handle token expiration in the fetch loop?

This looks like a misunderstanding of the cursor pagination model; nextPageToken is ephemeral by design to prevent race conditions, so you must chain requests immediately in a loop rather than storing tokens for later batch processing.

async function fetchAllDetails(queryParams: any) {
 let allDetails = [];
 let nextPageToken = undefined;
 do {
 const response = await platformClient.AnalyticsApi.postAnalyticsConversationsDetailsQuery({
 body: { ...queryParams, nextPageToken }
 });
 allDetails.push(...response.entity.conversations);
 nextPageToken = response.entity.nextPageToken;
 } while (nextPageToken);
 return allDetails;
}

Implement this synchronous loop in your renderer process to ensure the token remains valid throughout the aggregation cycle.

How I usually solve this is by chaining requests immediately in a Python loop to avoid token expiry. Storing tokens for batch processing breaks the cursor logic.

Warning: Do not mix page and nextPageToken parameters.

check your retry loop. nextPageToken is strictly cursor-based, so you must consume it immediately. mixing it with page offsets breaks the query.

This is typically caused by the ephemeral nature of the nextPageToken in cursor-based pagination. The token expires quickly to prevent race conditions, so you must chain requests immediately in a loop. Do not store tokens for later batch processing.

async function fetchAllConversations(apiClient, initialParams) {
 let allResults = [];
 let currentParams = { ...initialParams };
 
 do {
 const response = await apiClient.AnalyticsApi.postAnalyticsConversationsDetailsQuery(currentParams);
 allResults = allResults.concat(response.body.entities);
 
 if (response.headers['nextpagetoken']) {
 currentParams.nextPageToken = response.headers['nextpagetoken'];
 } else {
 break;
 }
 } while (response.headers['nextpagetoken']);
 
 return allResults;
}

Ensure you pass the nextPageToken from the headers directly into the next request body. Mixing offset parameters with cursor tokens breaks the query logic.