Pagination
How lists work. The list object, limit up to 100, the cursor parameter, next_cursor, and a loop that reads every page in TypeScript and Python.
Every endpoint that returns many things returns the same shape.
{
"object": "list",
"data": [ { "object": "order", "id": "ord_4821" } ],
"has_more": true,
"next_cursor": "bzoyMA"
}
datais the page.has_moresays whether there is another page.next_cursoris what to send to get it. It isnullon the last page.
#Ask for a page
| Parameter | Does |
|---|---|
limit |
How many items. 1 to 100. Default 20. |
cursor |
The next_cursor of the previous page. Leave it out for the first page. |
curl "https://adv.heliosynctech.com/api/v1/cases/SBXX010000032026/orders?limit=50" -H "Authorization: Bearer $AOS_KEY"
curl "https://adv.heliosynctech.com/api/v1/cases/SBXX010000032026/orders?limit=50&cursor=bzoyMA" -H "Authorization: Bearer $AOS_KEY"
A cursor is an opaque string: send back exactly the next_cursor you were given. Do not build or edit one, and do not keep one for days: it points at a place in the list, and the list can change. A cursor that is not from that list gives 400 invalid_cursor. Cursors look different from list to list (an offset, a watch id like wch_41, a report id, an event id, a request id); that is why they are not for you to make.
The event log, GET /events, also takes after, an event id, so a reader can resume from the last event it handled; its next_cursor is the id of the last event on the page and works as after too. It lists oldest first; every other list is newest first.
#Read every page
async function* all(path: string, params: Record<string, string> = {}) {
let cursor: string | null = null;
do {
const qs = new URLSearchParams({ limit: "100", ...params, ...(cursor ? { cursor } : {}) });
const res = await fetch(`${process.env.AOS_API_BASE}${path}?${qs}`, {
headers: { Authorization: `Bearer ${process.env.AOS_KEY}` },
});
const page = await res.json();
if (!res.ok) throw new Error(`${page.error.code}: ${page.error.message}`);
yield* page.data;
cursor = page.has_more ? page.next_cursor : null;
} while (cursor);
}
for await (const order of all("/cases/SBXX010000032026/orders")) console.log(order.id);
import os, requests
def all_items(path, **params):
cursor = None
while True:
q = {"limit": 100, **params, **({"cursor": cursor} if cursor else {})}
res = requests.get(
os.environ["AOS_API_BASE"] + path,
params=q,
headers={"Authorization": f"Bearer {os.environ['AOS_KEY']}"},
timeout=30,
)
page = res.json()
if not res.ok:
raise RuntimeError(page["error"]["message"])
yield from page["data"]
if not page["has_more"]:
return
cursor = page["next_cursor"]
for order in all_items("/cases/SBXX010000032026/orders"):
print(order["id"])
#Cost
A page is billed as the endpoint says. A free list (GET /cases/{cnr}/orders, GET /watches, GET /events) is free on every page. A priced search (GET /cases, GET /judgments) is billed per request, not per row, so limit=100 costs the same as limit=20 and is cheaper per row.
#Which endpoints are lists
GET /cases, GET /cases/{cnr}/orders, GET /cause-lists, POST /cause-lists/match, GET /tribunal-orders, GET /courts, GET /case-types, GET /holidays, GET /judgments, the citing list of a citator, GET /limitation/rules, GET /reports, GET /watches, GET /webhook-endpoints, GET /events, GET /usage and the GET /workspace/* lists. All take limit (1 to 100, default 20) and cursor.