Pagination & filtering
List endpoints return a collection of resources for your organization under a consistent envelope. This page documents the response shape these endpoints return, the ordering you can rely on, the paging scheme each uses, and the filters each one supports.
Two paging styles
GET /posts and GET /social-accounts use keyset (cursor) pagination: pass limit (default 25, max 100) and follow the next_cursor in each response. GET /media uses offset pagination (limit + offset) and returns a pagination block with the total count. All list calls return 200 with a top-level data array (empty as { "data": [] }, never a 404).The list envelope
Every list endpoint wraps its results in a top-level data array. Each element is the resource object for that endpoint. Cursor-paginated endpoints add a next_cursor field; the offset-paginated media endpoint adds a pagination object.
{
"data": [
{ "id": "…", "created_at": "2026-06-14T12:20:00.000Z" },
{ "id": "…", "created_at": "2026-06-13T18:05:00.000Z" }
],
"next_cursor": "WyIyMDI2LTA2LTEzVDE4OjA1OjAwLjAwMFoiLCIuLi4iXQ"
}When there are no more rows, next_cursor is null. The cursor is opaque and signed— it encodes the last row’s (created_at, id) as a base64url payload with an HMAC signature appended (payload.signature), so it cannot be forged or hand-constructed. Treat it as a black box: pass it back verbatim as ?cursor=… and never parse, edit, or build one yourself. A malformed, unsigned, or tampered cursor returns 400 (Invalid cursor); its internal format is not part of the API contract and may change.
Ordering
Cursor-paginated lists are ordered by (created_at desc, id desc) — newest first, with id as a stable tiebreaker so rows with identical timestamps page deterministically. GET /media is ordered by created_at desc.
List social accounts
GET /social-accounts — keyset pagination.
Returns connected accounts for your organization, newest first, excluding disconnected ones. All filters below combine with AND.
| Query parameter | Type | Required | Description |
|---|---|---|---|
limit | integer | No | Page size, clamped to 1–100 (default 25). |
cursor | string | No | Opaque keyset cursor from a previous response’s next_cursor. |
id | uuid | No | Return only the account with this id. |
tenant_id | string | No | Only return accounts associated with this end tenant. |
platform | enum | No | Only return accounts for this platform (e.g. x, linkedin, youtube). |
username | string | No | Exact-match account username. |
network_unique_id | string | No | Exact-match platform-side account id (also accepted as networkUniqueId). |
# First page (default 25)
curl "https://api.postfuze.com/api/v1/social-accounts" \
-H "Authorization: Bearer sk_live_…"
# Filter by platform and tenant, larger page
curl "https://api.postfuze.com/api/v1/social-accounts?platform=x&tenant_id=tenant_42&limit=100" \
-H "Authorization: Bearer sk_live_…"
# Next page
curl "https://api.postfuze.com/api/v1/social-accounts?cursor=WyIyMDI2…" \
-H "Authorization: Bearer sk_live_…"{
"data": [
{
"id": "a1b2c3d4-0000-4a9f-9b1c-2e7d6f0a1234",
"platform": "x",
"tenant_id": "tenant_42",
"network_unique_id": "1834567890",
"username": "acme",
"display_name": "Acme Inc.",
"status": "active",
"created_at": "2026-06-01T09:30:00.000Z",
"updated_at": "2026-06-14T12:00:00.000Z"
}
],
"next_cursor": null
}See Social Accounts for the full account object.
List posts
GET /posts — keyset pagination.
Returns your posts, newest first, excluding deleted ones. Each element is a summary object — id, status, is_draft, scheduled_at, published_at, and created_at. To get the full container hierarchy and per-account targets for a post, retrieve it by id.
| Query parameter | Type | Description |
|---|---|---|
limit | integer | Page size, clamped to 1–100 (default 25). |
cursor | string | Opaque keyset cursor from a previous response’s next_cursor. |
status | enum | One of draft, scheduled, queued, publishing, published, partial, failed, canceled. |
platform | enum | Posts with at least one target on this platform. |
social_account_id | uuid | Posts targeting this connected account. |
created_after / created_before | ISO 8601 | Half-open [after, before) range on created_at. |
scheduled_after / scheduled_before | ISO 8601 | Half-open [after, before) range on scheduled_at. |
# Scheduled posts for one account, scheduled in a window
curl "https://api.postfuze.com/api/v1/posts?status=scheduled&social_account_id=a1b2c3d4-…&scheduled_after=2026-06-15T00:00:00Z&scheduled_before=2026-06-22T00:00:00Z" \
-H "Authorization: Bearer sk_live_…"{
"data": [
{
"id": "p1a2b3c4-0000-4a9f-9b1c-2e7d6f0a1234",
"status": "scheduled",
"is_draft": false,
"scheduled_at": "2026-06-16T15:00:00.000Z",
"published_at": null,
"created_at": "2026-06-14T12:20:00.000Z"
}
],
"next_cursor": "WyIyMDI2…"
}See Post lifecycle for what each status means.
List media
GET /media — offset pagination.
Returns your uploaded media assets, newest first. Unlike the cursor-paginated endpoints, media paging uses limit + offset and returns a pagination object carrying the page parameters and the total matching count.
| Query parameter | Type | Description |
|---|---|---|
limit | integer | Page size, clamped to 1–100 (default 25). |
offset | integer | Number of items to skip (default 0). |
kind | enum | One of image, video, gif, document, audio. |
status | enum | Media status filter (e.g. ready, pending_upload). |
{
"data": [ { "id": "…", "kind": "image", "status": "ready", "created_at": "2026-06-14T12:20:00.000Z" } ],
"pagination": { "limit": 25, "offset": 0, "total": 137 }
}See Media for the full media object.
Other list endpoints
GET /social-networks returns your configured BYOK OAuth apps under a data array, newest first. See Social Networks for its object shape.
Reading every page
For the cursor-paginated endpoints, keep calling with the previous response’s next_cursor until it comes back null. The example below walks every page of GET /posts.
type PostSummary = { id: string; status: string; created_at: string };
async function* allPosts(params: Record<string, string> = {}): AsyncGenerator<PostSummary> {
let cursor: string | null = null;
do {
const qs = new URLSearchParams({ ...params, limit: '100', ...(cursor ? { cursor } : {}) });
const res = await fetch(`https://api.postfuze.com/api/v1/posts?${qs}`, {
headers: { Authorization: `Bearer ${process.env.POSTFUZE_API_KEY}` },
});
if (!res.ok) throw new Error(`List failed: ${res.status}`);
const body = (await res.json()) as { data: PostSummary[]; next_cursor: string | null };
yield* body.data;
cursor = body.next_cursor;
} while (cursor);
}
let n = 0;
for await (const _post of allPosts({ status: 'published' })) n += 1;
console.log(`Loaded ${n} published posts`);Offset paging for media
GET /media, increment offset by your limit until offset + data.length reaches pagination.total.