Pagination
Every list endpoint uses cursor-based pagination. There are no offset or page-number alternatives.
The list envelope
{
"object": "list",
"url": "/v1/cards",
"data": [
{ "id": "card_01HX8ZQ2K4M7P9RSTV", "object": "card" },
{ "id": "card_01HX8ZQ2K4M7P9RSTW", "object": "card" }
],
"has_more": true,
"next_cursor": "eyJpZCI6ImNhcmRfMDFIWDhaUTJLNE03UDlSU1RXIn0"
}
| Field | Meaning |
|---|---|
data | The current page. Always an array, though it can be empty |
has_more | Whether there are more results |
next_cursor | Pass this as starting_after to fetch the next page. null when has_more is false |
Paging forward
Start with the first page:
curl "https://api.aletaplanet.com/v1/cards?limit=50" \
-H "Authorization: Bearer $ALETA_ACCESS_TOKEN"
Then use the returned next_cursor for the next page:
curl "https://api.aletaplanet.com/v1/cards?limit=50&starting_after=eyJpZCI6…" \
-H "Authorization: Bearer $ALETA_ACCESS_TOKEN"
Keep going until has_more is false.
Don't use an empty data array as your stopping condition. A filtered page can
be empty even when more results are available.
Parameters
| Parameter | Type | Default | Max | Notes |
|---|---|---|---|---|
limit | integer | 25 | 100 | Values above the maximum are rejected, not clamped |
starting_after | string | Cursor for the next page | ||
ending_before | string | Cursor for the previous page |
starting_after and ending_before can't be used together.
Cursors
Cursors are opaque. Don't decode them, create your own, or rely on their internal format. The encoding isn't part of the API contract and can change.
A cursor is valid for 24 hours. After that, the API returns 400 with
expired_cursor. Start the traversal again with a fresh cursor.
Why not offsets
Offsets seem simple, but they can cause problems when the collection is changing.
For example, if new records are added between fetching page 1 and page 2, an offset-based page 2 can repeat records you've already seen or skip records entirely. On a transaction list, that could mean silently missing transactions during reconciliation.
Cursors point to a position in a stable sort, so the page boundary stays consistent even as new records are added.
The trade-off is that you can't jump directly to page 47. If you need that kind of UI, a narrower filter is usually a better approach.
Iterating safely
async function* allCards(aleta, params = {}) {
let cursor;
do {
const page = await aleta.cards.list({
...params,
limit: 100,
starting_after: cursor
});
yield* page.data;
cursor = page.next_cursor;
} while (cursor);
}
There are two things to keep in mind:
- Loop on
next_cursor, notdata.length. - Don't parallelize a traversal. Each page gives you the cursor needed to request the next one, so the requests are sequential by design.
For very large exports, use the reports endpoints instead of walking the API page by page. A complete transaction history is better treated as a file than as one huge list traversal.