Data API
Pagination
Every list endpoint answers with a meta block. Read it rather than counting.
meta
{
"limit": 2,
"offset": 0,
"sort": "skill",
"tier": "enterprise",
"next_cursor": "MS45Nzk1MzI2NzM5NzEzMjY4fDB4YjkwMTJlMGQ5YjYw...",
"has_more": true,
"note": "quality_score is a historical activity signal, not a return forecast."
}Parameters
| Name | Type | Description |
|---|---|---|
limit | int | Rows per page. Ask for as many as you can use — a page of 100 costs the same one credit as a page of 10. |
offset | int | Skip N rows. Fine for the first few pages; see the warning below. |
cursor | string | Opaque token from meta.next_cursor. The correct way to walk a whole list. |
meta fields
| Name | Type | Description |
|---|---|---|
has_more | bool | Whether another page exists. This — not the row count — is how you know when to stop. |
next_cursor | string | null | Pass back as ?cursor= for the next page. |
sort | string | The ordering actually applied, which may not be the one you asked for. |
tier | string | The plan this response was served under. |
note | string? | Occasional caveat about the data itself. Worth logging. |
Use the cursor for anything deep. Offset paging asks the database to count past every skipped row, so it slows down the further you go — and if the underlying ranking shifts between requests, rows can repeat or be missed. A cursor is anchored to a position in the result set and has neither problem.
Walking a full list
JavaScript
async function* everyWallet(pageSize = 100) {
let cursor = null;
do {
const qs = new URLSearchParams({ limit: String(pageSize) });
if (cursor) qs.set('cursor', cursor);
const res = await fetch(`${BASE}/v1/wallets?${qs}`, {
headers: { 'X-API-Key': KEY },
});
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const { wallets, meta } = await res.json();
yield* wallets;
// has_more is the stop condition. A short page is not the end of the list.
cursor = meta.has_more ? meta.next_cursor : null;
} while (cursor);
}
for await (const w of everyWallet()) {
console.log(w.address, w.skill_score);
}Python
def every_wallet(page_size=100):
cursor = None
while True:
params = {"limit": page_size}
if cursor:
params["cursor"] = cursor
r = requests.get(f"{BASE}/v1/wallets", params=params,
headers={"X-API-Key": KEY}, timeout=30)
r.raise_for_status()
body = r.json()
yield from body["wallets"]
meta = body["meta"]
if not meta.get("has_more"):
return
cursor = meta["next_cursor"]Cursors are opaque and short-lived — treat them as a token to hand straight back, never as something to store, parse or construct.