Pagination
Research Data API list operations return a pagination object alongside data:
{
"data": [],
"pagination": {
"next_cursor": "eyJvZmZzZXQiOjEwMH0=",
"has_more": true
},
"request_id": "77da54ed-2452-44f7-a857-f9a5ba5e7a51"
}
cursoris the optional query parameter used to request the next page. Omit it on the first request.next_cursoris the value to pass ascursoron the next request. It isnullafter the final page.has_morestates whether another page is available.
Cursors are opaque. Do not parse, construct, decode, or modify them. Pass each next_cursor value
through exactly as the API returned it.
Retrieve a complete collection
This Node.js example starts without a cursor and continues until has_more is false:
const accessToken = process.env.OPTIMAL_ACCESS_TOKEN;
const apiBaseUrl = 'https://api.optimalworkshop.com/api/research/v1';
async function fetchAll(path) {
const records = [];
let cursor;
while (true) {
const url = new URL(`${apiBaseUrl}${path}`);
if (cursor) {
url.searchParams.set('cursor', cursor);
}
const response = await fetch(url, {
headers: {
Accept: 'application/json',
Authorization: `Bearer ${accessToken}`,
},
});
if (!response.ok) {
throw new Error(`Research Data API request failed with ${response.status}`);
}
const page = await response.json();
records.push(...page.data);
if (!page.pagination.has_more) {
break;
}
cursor = page.pagination.next_cursor;
if (!cursor) {
throw new Error('The API reported another page without returning next_cursor');
}
}
return records;
}
async function main() {
const researchActivities = await fetchAll('/research_activities');
console.log(`Retrieved ${researchActivities.length} research activities`);
}
main().catch((error) => {
console.error(error);
process.exitCode = 1;
});
Checking has_more before reading next_cursor lets the loop end safely when the final
next_cursor is absent or null. The additional cursor check prevents an accidental infinite loop
if an incomplete pagination envelope is received.
Paginated operations
Use the same loop for each versioned list operation:
- List research activities
- List research activity participants
- List research activity responses
- List research activity insights
Participant, response, and insight paths also require a research_activity_id path parameter.