HyphaBase

Long lists

Sarah has 300 customers and you get 15 at a time. How to ask for the next page, and how to walk the whole lot.

Ask for Sarah's customers and you get fifteen. That's on purpose — nobody wants three hundred rows on a phone, and nobody wants us to build the response for thirty thousand either.

Two parameters control it:

ParameterDefaultNotes
page1Starts at 1, not 0
per_page15Up to 100. Ask for more and you quietly get 100.
curl "https://api.hyphabase.com/api/modules/clients?page=2&per_page=50" \
  -u sk_live_xxx: \
  -H "X-Location-Id: $HYPHABASE_LOCATION_ID"

What comes back

{
  "data": [{ "id": "019aff…", "first_name": "Dana", "name": "Dana Whitfield" }],
  "links": { "first": "…?page=1", "last": "…?page=4", "prev": null, "next": "…?page=2" },
  "meta": { "current_page": 1, "from": 1, "to": 15, "last_page": 4, "per_page": 15, "total": 58 }
}

meta.total is the honest count of everything matching, which is what you put in "58 customers" at the top of a screen.

Drive your paging from meta, not links

Setup endpoints — sites, staff, keys — return a leaner envelope with no links object, just data and a four-field meta. If you write one pagination helper for the whole API, base it on meta.current_page and meta.last_page, which both shapes always have. Following links.next works for business data and hands you undefined on setup data.

Walking the whole list

For a screen, fetch a page at a time and let the person ask for more. Pulling all three hundred to render fifteen is wasted work and a slow first paint.

async function loadPage(page) {
  const params = new URLSearchParams({ page, per_page: '25' });

  const response = await fetch(
    `https://api.hyphabase.com/api/modules/clients?${params}`,
    { credentials: 'include', headers: { 'X-Location-Id': locationId } },
  );

  const { data, meta } = await response.json();

  return { customers: data, hasMore: meta.current_page < meta.last_page };
}

The catch on long walks

Paging is offset-based: page 2 means "skip 15, take 15". If someone adds a customer while your job is on page 4, everything shifts down one and a row can slip between pages unseen.

For a nightly sync that's usually fine. When it isn't:

  • Filter to a closed date range, so the result set can't grow underneath you.
  • Check meta.total afterwards against what you processed, and re-run if they disagree.
  • For customers specifically, export instead. There are proper bulk endpoints — see Moving lots of customers at once. Don't page three hundred times to build a copy.

Next

On this page