Skip to main content

API reference

Pagination

Cursor-based pagination across list endpoints — request shape, response envelope, and end-of-stream signaling.

Last updated

Jobby.dev list endpoints use cursor-based pagination — you ask for limit rows, get back data plus a next_cursor, and pass that cursor back to fetch the next page. No offset / page- number indexing, ever; cursors stay stable as new rows land.

Request shape

List endpoints accept two query parameters:

  • limit — max rows per page. Default 25, max 100. Endpoints below 100 max are documented in the OpenAPI spec.
  • cursor— opaque string from the previous response's next_cursor. Omit on the first request.
# First page
curl 'https://jobby.dev/api/v1/billing/invoices?limit=25' \
  -H 'Authorization: Bearer jbb_...'

# Next page
curl 'https://jobby.dev/api/v1/billing/invoices?limit=25&cursor=eyJrIjoiYWJjMTIzIn0' \
  -H 'Authorization: Bearer jbb_...'

Response shape

{
  "data": [ ...rows... ],
  "next_cursor": "eyJrIjoiYWJjMTIzIn0",
  "has_more": true
}
  • data — the rows for this page, in stable sort order (newest-first unless documented otherwise).
  • next_cursor — pass this back as the cursor query param to get the next page. Treat the string as opaque — its internal shape is not part of the v1 contract.
  • has_more — boolean. false means you're at the end. When has_more is false, next_cursor is omitted.

Stability under writes

Cursors are stable across writes that happen between page fetches. New rows added between page 1 and page 2 don't shift your view — you'll see them on a future fetch with a fresh first-page request, but they don't cause page-2 rows to appear twice or get skipped.

Trade-off: cursors are tied to a sort order. If the underlying row is deleted between page fetches, the cursor still works (it skips cleanly to the next available row); but if you re-sort the endpoint with a different filter mid-pagination, you need to restart from page 1.

Iterating to the end

Standard loop:

let cursor: string | undefined;
const all = [];
do {
  const url = new URL("https://jobby.dev/api/v1/billing/invoices");
  url.searchParams.set("limit", "100");
  if (cursor) url.searchParams.set("cursor", cursor);
  const res = await fetch(url, { headers: { Authorization: `Bearer ${token}` } });
  const body = await res.json();
  all.push(...body.data);
  cursor = body.has_more ? body.next_cursor : undefined;
} while (cursor);

Endpoints that don't paginate

A few endpoints return all rows unconditionally — webhook deliveries (capped at 50 most recent), billing status (single row). Their OpenAPI entries document this. If a list response doesn't carry has_more, it's not paginated.

Related reading