# Pagination

Every list endpoint pages by keyset, with the same two parameters:

- `limit` — page size, 1–100 (default 20).
- `cursor` — where to continue from. Omit it (or pass `0`) for the first page.

Each page reports how to continue:

```json
{
  "invoices": [ ... ],
  "hasMore": true,
  "nextCursor": 4177
}
```

Pass `nextCursor` back as `cursor` until `hasMore` is `false`. That loop is
the same code on every list in this API.

Keyset paging is stable under concurrent inserts: new rows appear on the first
page of a fresh iteration and never shift the pages of an iteration already in
flight.

## Direction is a property of the list, not of the parameter

The lists do not all walk the same way, and that part is deliberate:

| List | Order | A cursor means |
| --- | --- | --- |
| `/invoices`, `/subscriptions` | Newest first | ids **below** the cursor |
| The credit ledger on `/contracts/{contractId}/credits` | Newest first | ids **below** the cursor |
| `/contracts` | Ascending contract id | ids **above** the cursor |

Contracts walk forward because the id is a stable identity to iterate, not a
recency ranking. What used to differ as well was the parameter NAME —
`beforeId` on some lists, `afterId` on others — so anyone who wrote a working
loop for invoices wrote a broken one for contracts. `cursor` and `nextCursor`
are the same on all of them; only the documented order changes.

The credit ledger pages the `entries` array only: the balances in the same
response are always complete. Seller-wide credit balances are one row per
currency and credit type, so that list is genuinely bounded and does not page.

## The original parameter names

`beforeId` / `nextBeforeId` and `afterId` / `nextAfterId` still work,
unchanged, on the lists that had them, and every response still carries the
original field beside `nextCursor` with the same value. Existing integrations
need no change. Sending both `cursor` and the original name with **different**
values is a `400` rather than a silent choice between them.

## Dates

`issuedFrom` and `issuedTo` accept a calendar date (`2026-08-01`) or a full
RFC 3339 timestamp. A bare date is read as **UTC midnight**, and the range is
half-open — `issuedFrom` inclusive, `issuedTo` exclusive — so adjacent months
never double-count a document. If your books close in a non-UTC zone, send the
timestamp form with your offset rather than the bare date.

## Amounts

All monetary amounts are **integers in the currency's minor units**
(`grandTotalMinor: 12050` is €120.50 for a EUR document). Quantities and tax
rates are decimal strings. Never parse amounts as floating point.
