Guides
Pagination
Lists return data and next_cursor. Continue until next_cursor is null, even when a filtered page is empty.
Cursors
limit defaults to 50 and accepts 1–200. Cursors are opaque and bound to the connection, route, filters and location access; preserve the same filters on later calls. There is no has_more field on REST pages.
Modern source rows are ordered by updatedAt then document id, ascending. A bounded legacy suffix scans records without a canonical timestamp in document-id order, so that suffix may contain older or newer effective times. Each request scans at most 500 raw source rows; filtering can produce short or empty data with a non-null next_cursor.
Swimmer pages expand source families into child records, with children sorted by id; the cursor can resume inside a family. Waiver pages similarly expand templates into per-swimmer status. These are not frozen snapshots: concurrent school changes can affect later pages.
Walk every page
const records = [];
let cursor = null;
do {
const query = new URLSearchParams({limit: '200'});
if (cursor) query.set('cursor', cursor);
const response = await fetch('https://api.swum.ai/v1/families?' + query, {
headers: {Authorization: `Bearer ${process.env.SWUM_API_KEY}`},
});
if (!response.ok) throw new Error(await response.text());
const page = await response.json();
records.push(...page.data);
cursor = page.next_cursor;
} while (cursor !== null);Deduplicate by record id and use overlapping update windows if your sync must tolerate concurrent writes. Do not stop because a page contains fewer than limit records.
Keep a copy in sync
updated_since requires an ISO 8601 timestamp with an explicit time zone. It applies to list results using effective update time: a valid stored updatedAt when present; otherwise the latest suitable progress, response, decline, check-in, created or Firestore snapshot update/create time. Family effective times also include resolved location-affinity metadata changes. Expanded swimmer/waiver rows filter their own effective time so a newer child is not hidden by an older parent/template.
Single-object family, swimmer, class and progress reads return the current object; updated_since is validated there but does not suppress that object. Use webhooks plus periodic reconciliation; neither a page nor a single webhook is a complete historical export.