API guides
Pagination
Lists are paginated with opaque cursors. A page is an object with items and next_cursor; next_cursor is null on the last page.
{
"items": [{ "id": "0190f5e2-4c1d-7a3b-8c2d-5e6f7a8b9c0d", "title": "Dark mode", … }],
"next_cursor": "<opaque string, or null on the last page>"
}Get the next page
Send next_cursor back as the cursor query parameter with the same filters and sort. limit sets the page size; each operation lists its range and default (usually 1–100, default 25).
curl "https://api.upvoiced.com/v1/posts?limit=100&cursor=$NEXT_CURSOR" \
-H "Authorization: Bearer $UPVOICED_API_KEY" \
-H "X-Workspace: $UPVOICED_WORKSPACE_ID"- Treat cursors as opaque strings: do not build or edit them.
- A cursor belongs to its query. A cursor that does not match the filters and sort, or a malformed one, answers
400 invalid_cursor. - Keep paging until
next_cursorisnull; a page may hold fewer items thanlimit.
With the SDK
paginate() follows the cursors for you, one page at a time:
import { UpVoiced } from '@upvoiced/sdk';
const apiKey = process.env['UPVOICED_API_KEY']; // uv_live_… (Settings → API keys)
const workspace = process.env['UPVOICED_WORKSPACE_ID']; // sent as X-Workspace
if (!apiKey || !workspace) throw new Error('Set UPVOICED_API_KEY and UPVOICED_WORKSPACE_ID.');
const upvoiced = new UpVoiced({ apiKey, workspace });
// Every item, fetching pages of 100 lazily; stop iterating to stop fetching.
for await (const post of upvoiced.paginate('/v1/posts', { query: { sort: 'top', limit: 100 } })) {
console.log(post.title, post.vote_count);
}
// Or one page at a time: pass next_cursor back as cursor until it is null.
let cursor: string | undefined;
do {
const page = await upvoiced.get('/v1/posts', {
query: { limit: 100, ...(cursor ? { cursor } : {}) },
});
for (const post of page.items) console.log(post.title);
cursor = page.next_cursor ?? undefined;
} while (cursor);
Paginated operations
GET /v1/public/boards/{slug}/postsGET /v1/public/posts/{slug}/commentsGET /v1/public/changelogGET /v1/unlisted/boards/{slug}/postsGET /v1/unlisted/posts/{id}/commentsGET /v1/widget/me/votesGET /v1/widget/me/followsGET /v1/widget/me/postsGET /v1/widget/postsGET /v1/widget/posts/{id}/commentsGET /v1/postsGET /v1/posts/{id}/commentsGET /v1/posts/{id}/followersGET /v1/changelogGET /v1/webhooks/{id}/deliveriesGET /v1/integrations/{id}/deliveriesGET /v1/reportsGET /v1/held-commentsGET /v1/blocks