Pagination
Every list endpoint accepts the same two query parameters and returns the same response envelope. Once you’ve integrated one list, you’ve integrated them all.
Query parameters
Section titled “Query parameters”| Parameter | Type | Default | Notes |
|---|---|---|---|
page | int | 1 | 1-based page number. Page 0 is invalid. |
pageSize | int | 20 | Items per page. Per-handler caps apply; large values are clamped or rejected with 400. |
A handful of read-heavy endpoints have a different default pageSize. The
Live API explorer is the source of truth for any specific
operation’s defaults — open the operation, look at the query-parameter
description.
Response envelope
Section titled “Response envelope”Every paginated response wraps Items in a PaginatedResult<T>:
{ "items": [ { "id": 1, "firstName": "Jane", "lastName": "Donor" }, { "id": 2, "firstName": "Sam", "lastName": "Smith" } ], "totalCount": 1834, "page": 1, "pageSize": 20}| Field | Meaning |
|---|---|
items | Items on this page in the order the handler returned them. |
totalCount | Total matching items across all pages (after filters, before paging). |
page | The page number the server actually served. |
pageSize | The page size the server actually served (may be clamped from your input). |
Walking every page
Section titled “Walking every page”Compute totalPages = ceil(totalCount / pageSize) and iterate. Don’t
rely on an empty items array as the stop signal — request the page you
expect to exist and check the count.
PAGE=1while :; do body=$(curl -sS \ -H "X-Api-Key: $AURA_API_KEY" \ "https://api.auradonors.com/api/tenants/$TENANT_ID/contacts?page=$PAGE&pageSize=100") echo "$body" | jq -r '.items[].id' total=$(echo "$body" | jq '.totalCount') size=$(echo "$body" | jq '.pageSize') pages=$(( (total + size - 1) / size )) [ "$PAGE" -ge "$pages" ] && break PAGE=$((PAGE + 1))doneFor a typed client:
public record PaginatedResult<T>(List<T> Items, int TotalCount, int Page, int PageSize);
async IAsyncEnumerable<ContactListItem> WalkContactsAsync(HttpClient http, Guid tenantId){ var page = 1; while (true) { var url = $"/api/tenants/{tenantId}/contacts?page={page}&pageSize=100"; var result = await http.GetFromJsonAsync<PaginatedResult<ContactListItem>>(url); if (result is null) yield break;
foreach (var item in result.Items) yield return item;
var totalPages = (int)Math.Ceiling((double)result.TotalCount / result.PageSize); if (page >= totalPages) yield break; page++; }}Worked example
Section titled “Worked example”curl -sS \ -H "X-Api-Key: $AURA_API_KEY" \ "https://api.auradonors.com/api/tenants/$TENANT_ID/contacts?page=2&pageSize=50"Returns the second page of 50 contacts. The same shape applies whether you’re paging contacts, donations, orders, payments, audit logs, shipments, or any other list endpoint.
Stable ordering
Section titled “Stable ordering”Each list endpoint declares its own ordering (most use newest-first by
CreatedAt). The order is stable for a given filter set as long as the
underlying data doesn’t change between requests. If you need a fully
consistent snapshot across pages, page through quickly — the platform
does not provide cursor or snapshot semantics today.
Deliberate non-goals
Section titled “Deliberate non-goals”- No cursor pagination. All endpoints are offset-based. A future v2 may introduce cursors for high-volume reads if real integrations need them.
- No Link header / RFC 5988 navigation. Compute next/prev from
totalCount,page, andpageSize. - No “page = 0 returns everything” escape hatch. If you need every row, walk every page.