Skip to content
Guides
API essentials

Pagination

Traverse result sets safely with opaque cursors.

List and query responses return data, has_more, and next_cursor. When has_more is true, pass next_cursor back unchanged. Stop when has_more is false.

The script below requires Node.js 18 or newer for built-in fetch. Set MICRO_TEAM_ID and MICRO_API_KEY first, then save it as paginate.mjs and run node paginate.mjs.

const teamId = process.env.MICRO_TEAM_ID;
const apiKey = process.env.MICRO_API_KEY;
if (!teamId || !apiKey) throw new Error("Set MICRO_TEAM_ID and MICRO_API_KEY");

let cursor;
do {
  const response = await fetch(
    `https://developers.micro.so/v2/prism/${teamId}/contact/query`,
    {
      method: "POST",
      headers: {"content-type": "application/json", "x-api-key": apiKey},
      body: JSON.stringify({query: {select: ["full_name", "email"], limit: 50, cursor}}),
    },
  );
  if (!response.ok) throw new Error(`Micro returned ${response.status}`);
  const page = await response.json();
  for (const record of page.data) console.log(record.id, record.properties);
  if (page.has_more && !page.next_cursor) {
    throw new Error("Invalid pagination response: has_more without next_cursor");
  }
  cursor = page.has_more ? page.next_cursor : undefined;
} while (cursor);

Cursors are opaque and currently offset-based. Do not parse them or reuse them with a changed filter or sort. Records added or removed during a long traversal can shift boundaries, so consistency-sensitive jobs should record processed IDs and make processing idempotent.

The page limit is capped at 50. Ask for totals only when needed: include_total costs an additional counting pass.

micro.so