API Reference (Max only)
Pagination

Pagination

All list endpoints in the Seller API use cursor-based pagination. There is no total count and no page number — just data and nextCursor.

Request parameters

Every list endpoint accepts:

ParameterTypeDefaultNotes
limitinteger50Maximum 100. Must be a positive integer.
cursorstringOpaque token returned by the previous page.

Example:

GET /v1/subscriptions?active=true&limit=25&cursor=eyJpZCI6MTAwfQ

Response shape

{
  "data": [
    { "id": "101", "...": "..." },
    { "id": "102", "...": "..." }
  ],
  "nextCursor": "eyJpZCI6MTAyfQ"
}
  • data — the page of results, in stable order.
  • nextCursor — pass back as cursor to fetch the next page. null means you've reached the end.

Iterating

const fetchAll = async (path, params = {}) => {
  const all = [];
  let cursor = null;
 
  do {
    const url = new URL(`https://subscord.com/api/v1/${path}`);
    Object.entries(params).forEach(([k, v]) => url.searchParams.set(k, v));
    url.searchParams.set("limit", "100");
    if (cursor) url.searchParams.set("cursor", cursor);
 
    const res = await fetch(url, {
      headers: { Authorization: `Bearer ${process.env.SUBSCORD_API_KEY}` },
    });
    if (!res.ok) throw new Error(`Request failed: ${res.status}`);
 
    const page = await res.json();
    all.push(...page.data);
    cursor = page.nextCursor;
  } while (cursor);
 
  return all;
};
 
const allActive = await fetchAll("subscriptions", { active: "true" });

Cursor format

Cursors are opaque to clients. Internally they are base64url-encoded JSON tokens that point to the last record of the previous page. Do not parse, mutate, or construct cursors yourself — the encoding may change.

If you send an invalid or malformed cursor, the API returns 400 invalid_request:

{
  "error": {
    "code": "invalid_request",
    "message": "Invalid cursor."
  }
}

Stability

Cursors point to a specific record, not an offset. New records inserted between requests do not shift your pagination — you will see them on a fresh listing only.

Cursors do not expire on a fixed timeline, but they are tied to the implicit ordering of the underlying list. Hold onto a cursor for hours or days at most.

Combining filters

Filter parameters (e.g. active, status, productId, createdAfter) compose with pagination, but the cursor only points to a position in the list — it does not remember which filters you applied.

Always re-send the same filters with each page. Changing filters mid-pagination will produce inconsistent results.

const params = { active: "true", productId: "42" };
let cursor = null;
do {
  const page = await fetchPage("/v1/subscriptions", { ...params, cursor });
  process(page.data);
  cursor = page.nextCursor;
} while (cursor);