Pagination
Lists (comments, Needs you and contacts) are paged with a cursor. Pages stay stable while new items arrive, so walking every page never skips or repeats one.
Updated September 26, 2026
How it works
Every list answers with data and next_cursor. Pass next_cursor back as cursor for the next page, with the same filters. next_cursor is null on the last page.
{ "data": [{ "id": "2a8d5bac-..." }], "next_cursor": "MjAyNi0wOS0yMlQxODoyMjozMS40MTIwMDBafDJhOGQ1YmFj" } limitis 1 to 100, default 50.- Cursors are opaque. Do not build or change one; a damaged cursor answers
400 invalid_request. - Lists are newest first. Comments page on
received_atthenid, Needs you oncreated_atthenid, contacts oncreated_atthenid, so items that arrive while you page land before your first page instead of shifting later ones.
Reading every page
Node.js
const base = 'https://commentgate.com/api/v1/comments?status=hidden&limit=100';
const headers = { authorization: `Bearer ${process.env.COMMENTGATE_API_KEY}` };
let cursor = null;
do {
const url = cursor ? `${base}&cursor=${encodeURIComponent(cursor)}` : base;
const res = await fetch(url, { headers });
if (res.status === 429) {
await new Promise((r) => setTimeout(r, Number(res.headers.get('retry-after')) * 1000));
continue;
}
const page = await res.json();
for (const comment of page.data) console.log(comment.id, comment.text);
cursor = page.next_cursor;
} while (cursor); Syncing new comments
To keep a copy up to date, store the newest received_at you have seen and ask for comments with since set to it. since is inclusive, so drop the one comment you already have. Contacts work the same way with updated_since.
curl "https://commentgate.com/api/v1/comments?since=2026-09-22T18:22:31.412Z&limit=100" \
-H "Authorization: Bearer $COMMENTGATE_API_KEY" For anything near real time, REST hooks push each comment to you within seconds instead.