Pagination | Moloni ON API
Moloni ONGuidesAPI ReferenceExplorer
Guides

Pagination

All list endpoints in the Moloni ON API support offset-based pagination through the options.pagination argument. This guide explains how pagination works, what defaults are applied, and how to page through large result sets.

How it works

List queries (e.g. customers, products, documents) accept an options argument containing a pagination object with two fields:

FieldTypeDescription
pageInt!The page number to retrieve (1-indexed)
qtyInt!The number of items per page

The response includes an options.pagination object with the same fields plus a count, the total number of matching records across all pages.

Defaults and limits

RuleValue
Default page1
Default qty50
Minimum page1 (values ≤ 0 are corrected to 1)
Minimum qty1 (values ≤ 0 are corrected to 1)
Maximum qty1000 (values above are capped to 1000)

If you omit pagination entirely, the API defaults to page 1 with 50 items.

Basic example

Fetch the first 10 customers:

query {
  customers(companyId: 1, options: {
    pagination: { page: 1, qty: 10 }
  }) {
    errors { field msg }
    data {
      customerId
      name
      vat
    }
    options {
      pagination {
        page
        qty
        count
      }
    }
  }
}

Response:

{
  "data": {
    "customers": {
      "errors": [],
      "data": [
        { "customerId": 1, "name": "João Silva", "vat": "123456789" },
        { "customerId": 2, "name": "Maria Santos", "vat": "987654321" }
      ],
      "options": {
        "pagination": {
          "page": 1,
          "qty": 10,
          "count": 127
        }
      }
    }
  }
}

In this example, there are 127 total customers. At 10 per page, that's 13 pages.

Calculating total pages

Use the returned count and qty to calculate the total number of pages:

totalPages = ceil(count / qty)

Using the example above: ceil(127 / 10) = 13 pages.

Paging through results

To fetch the next page, increment the page value:

query {
  customers(companyId: 1, options: {
    pagination: { page: 2, qty: 10 }
  }) {
    errors { field msg }
    data {
      customerId
      name
    }
    options {
      pagination { page qty count }
    }
  }
}

A typical loop to fetch all pages looks like this:

let page = 1;
const qty = 50;
let allRecords = [];

while (true) {
  const response = await fetch("https://api.molonion.pt/v1", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "Authorization": `Bearer ${accessToken}`,
    },
    body: JSON.stringify({
      query: `
        query {
          customers(companyId: 1, options: { pagination: { page: ${page}, qty: ${qty} } }) {
            errors { field msg }
            data {
              customerId
              name
            }
            options {
              pagination { page qty count }
            }
          }
        }
      `,
    }),
  });

  const { data } = await response.json();
  const result = data.customers;

  if (result.errors.length) {
    throw new Error(result.errors[0].msg);
  }

  allRecords.push(...result.data);

  const { count } = result.options.pagination;
  const totalPages = Math.ceil(count / qty);

  if (page >= totalPages) break;
  page++;
}

Pagination works alongside order and search within the same options object. Filters are applied before pagination, so count reflects the filtered total:

query {
  customers(companyId: 1, options: {
    pagination: { page: 1, qty: 20 }
    order: { field: name, sort: ASC }
    search: { field: ALL, value: "Silva" }
  }) {
    errors { field msg }
    data {
      customerId
      name
    }
    options {
      pagination { page qty count }
    }
  }
}

Here count returns only the number of customers matching the search, not the total customer count.

Omitting pagination

If you don't pass pagination at all, the API still paginates your results using the defaults (page 1, 50 items). Pagination is always applied to list endpoints.

# This returns the first 50 results by default
query {
  customers(companyId: 1) {
    data { customerId name }
  }
}

Next steps