Getting stuck on cursor pagination for analytics conversations query endpoint

We’ve got a python script that pulls compliance call data for our US/Eastern routing queues and the /api/v2/analytics/conversations/details/query endpoint keeps cutting off at two hundred rows. The page parameter gets ignored completely. Documentation talks about cursor pagination but I can’t figure out where to put the cursor value in the request body. It’s throwing a 400 bad request when I try passing it as a query parameter instead. The response JSON has a nextLink field but following it manually doesn’t fit our devops pipeline. I need the exact structure for the POST body when chaining requests together. Here is what I’m sending right now:

{
 "groupBy": ["routingQueueId"],
 "dateFrom": "2023-10-01T00:00:00.000Z",
 "dateTo": "2023-10-02T00:00:00.000Z",
 "page": 2,
 "pageSize": 500
}

You’re hitting the 200-row limit because the Analytics API enforces a hard cap per request when using the standard body pagination. The nextLink in the response is the key here, but you’re likely reconstructing the URL incorrectly or trying to pass the cursor as a separate query param, which breaks the signature.

The nextLink contains the pre-signed token and all necessary state. You shouldn’t be parsing it. Just use it as the full URL for the next GET request. Here is how I handle this in our Python service before piping the data into New Relic custom events.

import requests

def fetch_analytics_all(query_body, initial_url):
 all_data = []
 url = initial_url
 headers = {"Authorization": f"Bearer {access_token}", "Content-Type": "application/json"}

 while url:
 # First request is POST, subsequent are GET to nextLink
 if url == initial_url:
 response = requests.post(url, json=query_body, headers=headers)
 else:
 response = requests.get(url, headers=headers)

 if response.status_code != 200:
 raise Exception(f"API Error: {response.status_code}")

 data = response.json()
 all_data.extend(data.get('data', []))
 
 # Cursor is embedded in the nextLink
 url = data.get('nextLink')
 
 # Safety break to prevent infinite loops if nextLink is malformed
 if len(all_data) > 10000: 
 break
 
 return all_data

The gotcha is that the initial call must be a POST with the JSON body. Once you get the first nextLink, switch to GET requests without the body. If you keep sending the body with the GET, it fails. Also, check your OAuth scopes. You need analytics:call:view and analytics:conversation:view. If the token lacks those, the nextLink might return a 403 instead of data.

I track the request latency for these calls in New Relic APM. If the nextLink requests start timing out, it’s usually a sign the query range is too wide. Narrow the dateFrom and dateTo window to 24 hours. It’s slower but more reliable for high-volume queues.