Skip to main content

Developers · Guide

Pagination

Read a long list 50 records at a time with the limit, gt and lt parameters, in ascending id order.

Every list (GET /api/v2/funding_rounds, /funding_applications, /contracts, /registration_entities, /milestones) answers a bare JSON array of records in ascending id order, at most 50 at a time. There is no page number and no cursor: you page by id.

The parameters

Paging parameters
ParameterWhat it does
limitRecords per page. Default 50, at most 50: a larger value is read as 50. Not an integer, or below 1, answers 400 invalid_request with limit is invalid.
gtOnly records whose id is greater than this. Pass the last id you received to read the next page.
ltOnly records whose id is less than this.

Each parameter is an integer, sent once. A parameter that is not an integer, or is sent twice, answers 400 invalid_request naming it. A gt or lt that no id can meet is an empty page, not an error. A parameter a route does not document is ignored, except a filters[…] key the milestones list does not know, which is 400.

Read every page

  1. Ask for the first page with no gt.
  2. Keep the id of the last record on the page.
  3. Ask again with gt set to that id.
  4. Stop when a page holds fewer records than the limit: there are no more.
The first two pages
curl "https://your-org.backed.giving/api/v2/funding_applications?limit=50" -H "Authorization: Bearer $BACKED_TOKEN"
curl "https://your-org.backed.giving/api/v2/funding_applications?limit=50&gt=1287" -H "Authorization: Bearer $BACKED_TOKEN"
Node.js
async function* everyRecord(path, token) {
  let after = null;
  for (;;) {
    const query = new URLSearchParams({ limit: '50' });
    if (after !== null) query.set('gt', String(after));
    const response = await fetch(`https://your-org.backed.giving${path}?${query}`, {
      headers: { Authorization: `Bearer ${token}` },
    });
    if (!response.ok) throw new Error(`${path}: ${response.status}`);
    const page = await response.json();
    yield* page;
    if (page.length < 50) return;
    after = page[page.length - 1].id;
  }
}

for await (const application of everyRecord('/api/v2/funding_applications', token)) {
  console.log(application.id, application.state);
}

Filters, such as submitted=1 on funding applications or filters[ids][] on milestones, narrow the list before it is paged: keep sending them with every page.

The OData reporting feed pages differently: up to 1000 rows a page, each ending with `@odata.nextLink` while more remain. See Power BI.