Pagination
One cursor scheme for every list endpoint.
How it works
Every endpoint that returns a list paginates the same way. No exceptions.
Request — two optional query parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
limit | number | endpoint-specific | Max items to return. Each endpoint documents its default and maximum. |
cursor | string | — | Opaque token from a previous response. Omit it for the first page. |
Response — every list response has the same envelope:
{
"items": [ ... ],
"nextCursor": "eyJzaWciOiI1aDZ4QkVhdUozUEs2U1dDWjFQR2pCdmo4dkRkV0czS3B3QVRHeTFBUkFYRiJ9"
}When nextCursor is null, you've reached the end.
Example: walking a wallet's history
const base = "https://api.sarg.am/v1/solana";
const headers = { Authorization: `Bearer ${process.env.MAINLY_API_KEY}` };
let cursor: string | null = null;
do {
const url = new URL(`${base}/wallets/9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM/transactions`);
url.searchParams.set("limit", "100");
if (cursor) url.searchParams.set("cursor", cursor);
const page = await fetch(url, { headers }).then((r) => r.json());
process(page.items);
cursor = page.nextCursor;
} while (cursor);Rules
- Cursors are opaque. Don't parse, build, or modify them — their format can change without notice.
- Cursors expire. A cursor is valid for at least 10 minutes. Long-running
exports should tolerate a
cursor_expirederror by restarting from a recent checkpoint. - Ordering is stable and documented per endpoint. Transaction history is always newest-first.
Why this matters
Raw Solana tooling has four different pagination dialects: signature-based
before/until on RPC, page/limit and before/after cursors on asset
APIs, plain cursor on compression APIs, and before-signature query
parameters on parsed-history APIs — with different caps on each. Mainly hides
all of them behind the single scheme above.