Pagination
List endpoints return their rows in pages. Page with the cursor returned by
the previous response: each page then costs the same however far into the list
it is, and a row added while you page does not make another row appear twice or
go missing. Paging by page number still works, but is deprecated. From
2026-12-31, a list with more than 10,000 matching rows can only be paged past
its first page by cursor, so sort it by a column that pages by cursor (see
Lists that page by cursor) or narrow the filters
below the limit.
Paging with a cursor
Request the first page without a cursor. Each response carries nextCursor,
the cursor for the page after it, and hasMore. Pass nextCursor back as
cursor, with the same filters and sort, until nextCursor is null.
Code
Code
Code
A cursor is opaque: pass it back unchanged and do not build one yourself. It is
bound to the filters and sort of the request that returned it, so a request that
changes either is refused. limit may change between pages. Do not send page
together with cursor.
A row added during the walk is returned only if it sorts after the current
cursor. total counts every row that matches the filters and can lag behind
rows being added. Stop when nextCursor is null, not when you have read
total rows.
Lists that page by cursor
| Endpoint | Sorts that page by cursor |
|---|---|
GET /api/v1/journal-entries | date, createdAt (both ASC and DESC) |
GET /api/v2/draft-journal-entries | the list's fixed order |
GET /api/v1/invoices | the list's fixed order |
GET /api/v1/credit-notes | the list's fixed order |
GET /api/v1/quotes | createdAt, date, amount, status |
GET /api/v1/order-confirmations | createdAt, date, amount, status |
GET /api/v1/customers | the list's fixed order |
GET /api/v1/suppliers | the list's fixed order |
GET /api/v1/vendors (deprecated alias of suppliers) | the list's fixed order |
GET /api/v1/advisor/clients | the list's fixed order; the cursor is also bound to updatedAtFrom |
GET /api/v1/products | productNumber, name, createdAt |
GET /api/v1/subscriptions | the list's fixed order |
GET /api/v1/shipments | the list's fixed order |
GET /api/v1/stock/on-hand | the list's fixed order |
GET /api/v1/stock/movements | the list's fixed order |
A sort on a column that can be empty, such as documentDate on journal
entries or documentNumber and validUntil on quotes, cannot page by cursor:
its responses carry nextCursor: null even when hasMore is true, and a
request combining it with cursor is refused. Page such a sort by page
number while hasMore is true; from 2026-12-31 that works only while the list
has at most 10,000 matching rows, so narrow the filters or choose a sort from the
table above for a larger one. Each endpoint's parameters and defaults are in
the API Reference.
Paging by page number (deprecated)
page and limit page by position: page n skips the first (n - 1) × limit
matching rows. Every request past the first page reads the rows before it
again, so walking a large list this way slows with every page, and rows added
during the walk shift the pages under you. A page past the last one returns an
empty data array.
Paging by page number is deprecated and stays supported on lists of up to
10,000 matching rows. On a larger list, from 2026-12-31, a page past the first
is refused with 400 PAGINATION_OFFSET_TOO_DEEP. Page such a list by cursor
with a sort that supports it, or narrow the filters (for example a fromDate
window) to keep it under the limit.
A response to a request for a page past the first carries these headers:
| Header | Value | Sent | Meaning |
|---|---|---|---|
Deprecation | @1791417600 | always | Paging by page number was deprecated on 2026-10-08 (RFC 9745, Unix seconds). |
Link | <https://docs.ledgerbee.com/guides/pagination>; rel="deprecation" | always | This page. |
Sunset | Thu, 31 Dec 2026 00:00:00 GMT | lists with more than 10,000 matching rows | The date the request starts being refused (RFC 8594). |
Errors
| Condition | What you observe | Fix |
|---|---|---|
| The cursor was not returned by this endpoint, or the filters or sort changed since | 400 PAGINATION_INVALID_CURSOR | Restart from the first page with the new filters. |
cursor and page sent together | 400 PAGINATION_CURSOR_WITH_PAGE | Drop page. |
cursor sent with a sort that cannot page by cursor | 400 PAGINATION_CURSOR_SORT_NOT_SUPPORTED | Sort by a column listed in the table above. |
| A sort the endpoint lists but does not support | 400 PAGINATION_SORT_NOT_SUPPORTED | Choose another sortBy. |
| From 2026-12-31: a page past the first, by page number, on a list with more than 10,000 matching rows | 400 PAGINATION_OFFSET_TOO_DEEP | Page with cursor, or narrow the filters. |
| Error bodies follow the shape described in Errors. |