REST API Pagination in Follow Up Boss

By the Follow Up Ace team· Last updated
Quick answer

Follow Up Boss supports two pagination patterns: classic limit/offset for filtered list endpoints and keyset cursor pagination via _metadata.next for full database sweeps. The cursor value is an opaque token — not a URL — so you append it as ?next=<token> to your original endpoint. Page up to 100 records at a time and add a delay between pages to stay within rate limits.

Code editor displaying a REST API pagination loop for Follow Up Boss contacts endpoint

If you are building an integration, a data pipeline, or a bulk automation on top of Follow Up Boss, pagination is the first real engineering decision you have to make correctly. Get it wrong and you either silently drop records or hammer the API until you get rate-limited. This guide explains exactly how FUB's pagination works — with real request patterns drawn from production integrations.

Does Follow Up Boss use limit/offset or cursor pagination?

Follow Up Boss uses both, depending on the endpoint and use case. Understanding when each applies prevents subtle data loss bugs.

Pattern Parameter Best for Risk
Limit / offset ?limit=100&offset=0 Filtered pulls by tag, status, or date range Duplicate or missing records if the dataset mutates mid-sweep
Keyset cursor ?next=<cursor_token> Full database sweeps, decay detection, bulk analysis Cursor is opaque — do not parse it; just pass it back verbatim

How does limit/offset pagination work in the FUB API?

The /v1/people endpoint (and most list endpoints) accept limit and offset as query parameters. The maximum page size is 100 records. To pull all contacts tagged "Nurture" you would increment the offset by the page size until the response contains fewer records than the requested limit — that signals the last page.

Example request (Node.js):

const BASE = 'https://api.followupboss.com/v1/people';
const AUTH  = Buffer.from(`${apiKey}:`).toString('base64');

async function fetchPeopleByTag(tag) {
  const allPeople = [];
  let offset = 0;
  const limit  = 100;

  while (true) {
    const url = `${BASE}?limit=${limit}&offset=${offset}` +
                `&tags=${encodeURIComponent(tag)}&fields=allFields`;

    const res = await axios.get(url, {
      headers: { Authorization: `Basic ${AUTH}`, Accept: 'application/json' }
    });

    const page = res.data.people || [];
    allPeople.push(...page);

    if (page.length < limit) break; // last page
    offset += limit;

    await delay(1000); // 1 s between pages — respect rate limits
  }

  return allPeople;
}

This pattern mirrors what Follow Up Ace uses internally for tag-filtered pulls in its nurture scheduler (chat-app/firestore/functions/nurture.js, fetchPeopleByTag).

What is the keyset cursor in FUB and how do you use it?

For full-database sweeps — where you need to visit every contact regardless of tag or status — Follow Up Boss returns a cursor token in the response metadata. The response body includes a _metadata object with a next field. That value is an opaque string token, not a URL.

The critical mistake developers make: they try to call axios.get(response._metadata.next) directly. Because the cursor is not a URL, this throws an invalid URL error. The correct approach is to append the cursor as a next query parameter on your original endpoint URL.

Example (Node.js):

async function sweepAllContacts(authHeader) {
  const BASE = 'https://api.followupboss.com/v1/people';
  let nextCursor = null;
  let totalFetched = 0;

  do {
    const params = new URLSearchParams({
      limit: '100',
      sort: 'created',
      fields: 'allCustom',
    });
    if (nextCursor) params.set('next', nextCursor);

    const res = await axios.get(`${BASE}?${params}`, {
      headers: { Authorization: authHeader, 'Content-Type': 'application/json' }
    });

    const people = res.data.people || [];
    // process people here...
    totalFetched += people.length;

    // Extract the next cursor from _metadata
    nextCursor = res.data._metadata?.next || null;

    if (nextCursor) await delay(1000); // pace between pages
  } while (nextCursor);

  return totalFetched;
}

This pattern is directly derived from how Follow Up Ace's decay analysis worker sweeps the full contact database (chat-app/workers/aceIntelligenceDecayChildInitializerWorker.js, lines 116–168).

What is the maximum page size in Follow Up Boss?

The maximum value for the limit parameter is 100. Requests with a higher limit may be silently clamped or return an error — always code to the 100-record ceiling. Do not assume a large limit will return more than 100 records.

How do you handle Follow Up Boss API rate limits during pagination?

Follow Up Boss enforces rate limits at the API key level. The exact limits are documented in the official FUB API documentation and subject to change — verify current limits before production deployment. From production integration experience, the practical patterns that prevent rate-limit errors are:

  1. Add a delay between pages. A 1-second delay between page requests is a conservative baseline for bulk sweeps. You can reduce this if you are making fewer total requests per run.
  2. Respect 429 responses. When the API returns HTTP 429 (Too Many Requests), read the Retry-After header and wait that long before retrying. Do not immediately retry on 429.
  3. Implement exponential backoff. For transient errors (5xx responses), use exponential backoff with jitter rather than a fixed retry interval.
  4. Cap the records per run. For background workers, set a maximum number of contacts to process per execution and persist the cursor so the next run continues where the last one left off. Follow Up Ace caps its decay sweep at a configurable ACE_DECAY_MAX_CONTACTS_PER_RUN (default 1,000) and saves the resume cursor across runs.

How do you resume a pagination sweep that was interrupted?

This is the key operational advantage of cursor pagination over limit/offset. A cursor token represents a stable position in the ordered dataset. If your sweep is interrupted (worker crash, timeout, rate limit), you save the last successful cursor and resume from it on the next run — you do not have to start from offset=0.

Implementation pattern:

  1. Before starting the sweep, check your persistent store (Firestore, Redis, or a database) for a saved cursor
  2. If a saved cursor exists, start the sweep with ?next=<saved_cursor> instead of from the beginning
  3. After each successful page, immediately persist the cursor before processing the records — this way a crash during processing does not lose your place
  4. When the sweep reaches the end (no more _metadata.next), clear the saved cursor so the next scheduled run starts fresh

This "checkpoint" pattern is how Follow Up Ace implements its nightly account-wide intelligence sweeps — it covers the full database over multiple scheduled runs rather than in a single long-running process.

What fields should you request when paginating through contacts?

FUB's /v1/people endpoint returns a default set of fields unless you specify otherwise. For most integrations, you want to request only what you need:

Requesting the full allFields payload when you only need IDs and custom fields doubles your data transfer unnecessarily and slows large sweeps. Be specific about what you request.

How do you filter paginated results in the FUB API?

You can combine pagination parameters with filtering parameters in the same request. Common filter parameters for the /v1/people endpoint:

Filter parameter Example value Effect
tags Nurture Only contacts with this tag
sort created Order by creation date ascending
sort -updated Order by last update descending (prefix - = descending)
stage Active Clients Only contacts in this pipeline stage

Always verify current parameter names and supported values in the official FUB API documentation, as the API evolves. The patterns above reflect production usage; individual parameters may change.

What common pagination bugs should you test for?

For more on building robust FUB integrations, see Follow Up Boss API real-time integration explained and the guide on rate limiting basics for the FUB API. If you want to interact with FUB through natural language rather than raw API calls, the Follow Up Ace agentic layer exposes 215 MCP tools that handle pagination, authentication, and error handling for you.