How it works
Paged lists take limit and cursor as query parameters, and answer with next_cursor beside data. Pass it back unchanged to get the next page. When it is null, that was the last one.
Query parameters
limitinteger- How many to return, 1–200. Defaults to 50.
cursorstring- The
next_cursorfrom the previous page. Opaque — don't build or edit one; an edited cursor answers400.
curl "https://qarunbook.com/api/v1/issues?app=Checkout&limit=1" \
-H "Authorization: Bearer $QARUNBOOK_KEY"Response · 200
{
"data": [
{
"id": "mfr8w1c4d2e",
"app": {
"id": "mfq3k2p9x1a",
"name": "Checkout"
},
"check": {
"id": "mfq3k2qa7bc",
"ref": "AUTH-01",
"title": "Sign in with email and password"
},
"text": "The Sign in button does nothing on Safari 18. No error, no network request.",
"platforms": ["WL"],
"all_platforms": false,
"status": "open",
"raised_by": "Ada Lovelace via API",
"raised_at": "2026-09-27T16:02:11.482Z",
"reporter": {
"name": "Ada Lovelace",
"email": "ada@example.com"
},
"via": "api",
"edited_by": null,
"edited_at": null,
"fixed_by": null,
"fixed_at": null,
"attachments": []
}
],
"next_cursor": "eyJhdCI6IjIwMjYtMDktMjdUMTY6MDI6MTEuNDgyWiIsImlkIjoibWZyOHcxYzRkMmUifQ"
}Which lists are paged
- Issues — newest first. The cursor marks a place in time, so issues raised while you are paging never shift the pages you have not read yet. With
sort=fixed_at, most recently fixed first. - Results — most recently recorded first, the same way.
- Checks — in runbook order. Status is worked out fresh on every read, so a check filtered by status can move between pages if somebody records a result while you are paging.
- Apps and sections are not paged. A workspace has tens of them, not thousands, and they come back whole.
Reading every page
JavaScript
let cursor = null;
const all = [];
do {
const url = new URL("https://qarunbook.com/api/v1/issues");
url.searchParams.set("app", "Checkout");
url.searchParams.set("status", "all");
url.searchParams.set("limit", "200");
if (cursor) url.searchParams.set("cursor", cursor);
const res = await fetch(url, {
headers: { Authorization: `Bearer ${process.env.QARUNBOOK_KEY}` },
});
const { data, next_cursor } = await res.json();
all.push(...data);
cursor = next_cursor;
} while (cursor);Python
import os, requests
issues, cursor = [], None
while True:
params = {"app": "Checkout", "status": "all", "limit": 200}
if cursor:
params["cursor"] = cursor
body = requests.get(
"https://qarunbook.com/api/v1/issues",
params=params,
headers={"Authorization": f"Bearer {os.environ['QARUNBOOK_KEY']}"},
).json()
issues += body["data"]
cursor = body["next_cursor"]
if not cursor:
break