C# SDK pagination loop infinite on /api/v2/analytics/conversations/details/query

Trying to pull full conversation detail history using the .NET SDK (genesyscloud_platformclient). The endpoint is POST /api/v2/analytics/conversations/details/query.

The docs say:

“Use the cursor parameter to paginate through results. The response will contain a nextLink if more data is available.”

My code looks like this:

var request = new ConversationDetailQueryRequest();
request.TimeFilter = new DateRangeFilter() { Start = "2023-10-01T00:00:00Z", End = "2023-10-02T00:00:00Z" };

string nextLink = null;
do
{
 var response = await analyticsClient.PostAnalyticsConversationsDetailsQuery(request);
 // Process items
 nextLink = response.NextLink;
 // Docs imply we just pass the cursor from nextLink
 if (!string.IsNullOrEmpty(nextLink))
 {
 // Extract cursor from nextLink query string
 var uri = new Uri(nextLink);
 var query = HttpUtility.ParseQueryString(uri.Query);
 request.Cursor = query["cursor"];
 }
} while (nextLink != null);

The first request works fine. Returns 100 records. nextLink is present. I parse the cursor value and put it back in the request object. Second request returns the exact same 100 records. Same IDs. Same timestamps. The nextLink in the second response is identical to the first. It’s an infinite loop of the first page.

If I manually copy the nextLink URL from the first response and paste it into Postman as a GET request, it works perfectly. It returns the next 100 records. But doing it via the SDK’s PostAnalyticsConversationsDetailsQuery method with the cursor set on the request object just resets to page 1.

Is the SDK ignoring the Cursor property on subsequent calls? Or do I need to use a different method for follow-up requests? The docs don’t explicitly show C# examples for cursor pagination on this specific endpoint, just generic examples.

Also noticed that request.Size is ignored after the first call. Seems like the SDK might be reconstructing the request body and dropping the cursor or size parameters. Anyone hit this wall with the detail query endpoint?

You’re likely hitting the cursor trap. The SDK doesn’t auto-handle pagination for analytics queries like it does for standard entity lists. You have to manually extract the nextLink from the response and pass it back as the cursor.

If you just loop on hasMore, it’ll spin forever because the initial request never gets the cursor context.

Here’s the pattern that works in our hybrid setup:

var request = new ConversationDetailQueryRequest();
// ... setup your filters ...

ApiResponse<ConversationDetailQueryResponse> response = await analyticsApi.PostAnalyticsConversationsDetailsQueryAsync(request);

while (response.Body.NextLink != null)
{
 var nextRequest = new ConversationDetailQueryRequest();
 nextRequest.Cursor = response.Body.NextLink; 
 // Re-apply other filters if needed
 response = await analyticsApi.PostAnalyticsConversationsDetailsQueryAsync(nextRequest);
}

The NextLink contains the encoded cursor state. If you don’t send it back exactly as received, the API treats it as a fresh query. We hit this exact issue with NICE CXone data syncs last month.

Be careful with the nextLink parsing in the .NET SDK. It’s not just a simple string extraction. If the query parameters in the nextLink contain special characters or if the SDK version you’re using has a bug with URL decoding, you might end up sending a malformed cursor back.

The safer way is to use the PaginationLink helper if available, or manually parse the URL and reconstruct the request object. Here’s a safer loop structure that avoids the infinite spin and handles the cursor correctly:

var request = new ConversationDetailQueryRequest();
// ... set your filters ...

string cursor = null;
bool hasMore = true;

while (hasMore)
{
 if (cursor != null)
 {
 request.Cursor = cursor;
 }

 var response = await platformClient.AnalyticsApi.PostAnalyticsConversationsDetailsQuery(request);

 if (response == null || response.Results == null)
 {
 break;
 }

 foreach (var item in response.Results)
 {
 // cess item
 }

 // Check for next cursor
 if (response.NextLink != null && !string.IsNullOrEmpty(response.NextLink))
 {
 // Extract cursor from the nextLink URL
 // The nextLink looks like: /api/v2/analytics/conversations/details/query?cursor=abc123
 var uri = new Uri(response.NextLink);
 var query = System.Web.HttpUtility.ParseQueryString(uri.Query);
 cursor = query["cursor"];
 }
 else
 {
 hasMore = false;
 }
}

Also, keep an eye on the pageSize. If you set it too high, the API might timeout or return a 400. Stick to 100 or 200. And don’t forget to add a small delay between iterations if you’re hammering the API. Rate limits are real.

One more thing. If you’re pulling a lot of data, consider using the Bulk API if it’s available for your use case. It’s faster and less ne to pagination issues. But for now, this loop should work. Just test it with a small date range first.