Parsing JSON Responses in the Follow Up Boss API

By the Follow Up Ace team· Last updated
Update (July 2026): the Ace field set referenced below was consolidated on June 28, 2026. Ace now writes 6 model-grounded custom fields — Ace Win Score and Ace Churn Risk free on every account; Expected GCI (est.), Opportunity, Seller Tier, and Last Analyzed with Ace Trove. The legacy signals below are still computed internally and power the dashboards and ranked queue. See the current field-by-field guide.
Quick answer

The Follow Up Boss API returns standard JSON objects. List endpoints wrap results in a top-level array key (e.g., people) alongside a _metadata object for pagination. Single-resource calls return the object directly. Custom fields — including Ace Score fields written by Follow Up Ace — appear as named properties such as customAceScore and customAceTier on the contact object.

Developer parsing JSON API response from Follow Up Boss CRM in code editor

How the Follow Up Boss REST API returns data

Follow Up Boss exposes a REST API at https://api.followupboss.com/v1/. Every response body is JSON. The content type is always application/json. There is no XML option, no GraphQL endpoint, and no streaming format — just straightforward request/response JSON over HTTPS.

The response shape depends on whether you are fetching a collection or a single resource:

Authentication before you can parse anything

The API uses HTTP Basic Authentication. Your API key is the username; the password field is left blank. Every request must include an Authorization header or the server returns 401 before you even see a JSON body.

# Example: Base64-encode API_KEY: (note the trailing colon, no password)
# Then set the Authorization header on every request:
Authorization: Basic <base64(API_KEY:)>
Content-Type: application/json

Most HTTP libraries handle the base64 encoding automatically when you supply a username and empty password. Never embed the raw API key in client-side code or commit it to source control — store it in an environment variable.

JSON response structure for contacts and leads

The /v1/people endpoint is the primary resource for contacts and leads. A collection response looks like this (illustrative example — field names and shape match FUB's public documentation):

{
  "people": [
    {
      "id": 12345,
      "firstName": "Jordan",
      "lastName": "Rivera",
      "stage": "New Lead",
      "source": "Website",
      "created": "2026-06-01T09:22:00Z",
      "updated": "2026-06-20T14:05:00Z",
      "emails": [
        { "value": "[email protected]", "type": "home" }
      ],
      "phones": [
        { "value": "5551234567", "type": "mobile" }
      ],
      "customAceScore": 74,
      "customAceTier": "Warm",
      "customAceStatus": "Engaged",
      "customAceResponseTime": 8,
      "customAceVelocityScore": 61,
      "customAceDaysSinceInbound": 3,
      "customAcePreferredChannel": "sms"
    }
  ],
  "_metadata": {
    "total": 842,
    "limit": 25,
    "offset": 0
  }
}

Key fields to know when parsing contact objects:

Field Type Notes
id integer Stable unique identifier; use this for updates and lookups
firstName / lastName string May be null if the contact was created from a phone number only
emails / phones array of objects Each item has value and type; a contact may have multiple entries
stage string Pipeline stage label; values depend on your FUB configuration
source string Lead origin; drives action plan assignment in FUB
created / updated ISO 8601 string UTC timestamps; parse with your language's date library
custom* varies Custom fields appear as top-level properties with their configured name

Handling pagination in Follow Up Boss API responses

All list endpoints are paginated. The _metadata object in every collection response tells you how many total records exist and where your current page falls. Use limit and offset query parameters to walk through pages.

JavaScript pagination example

// Illustrative example — walks all contacts page by page
async function fetchAllPeople(apiKey) {
  const BASE = 'https://api.followupboss.com/v1/people';
  const auth = Buffer.from(`${apiKey}:`).toString('base64');
  const headers = { Authorization: `Basic ${auth}` };

  const limit = 100;
  let offset = 0;
  let total = Infinity;
  const results = [];

  while (offset < total) {
    const url = `${BASE}?limit=${limit}&offset=${offset}`;
    const res = await fetch(url, { headers });
    if (!res.ok) throw new Error(`FUB API error: ${res.status}`);

    const data = await res.json();
    total = data._metadata.total;
    results.push(...data.people);
    offset += limit;
  }

  return results;
}

Python pagination example

# Illustrative example using the requests library
import requests, os

def fetch_all_people(api_key):
    session = requests.Session()
    session.auth = (api_key, '')   # HTTP Basic Auth — password blank
    url = 'https://api.followupboss.com/v1/people'

    limit = 100
    offset = 0
    results = []

    while True:
        resp = session.get(url, params={'limit': limit, 'offset': offset})
        resp.raise_for_status()
        data = resp.json()

        results.extend(data['people'])
        total = data['_metadata']['total']
        offset += limit
        if offset >= total:
            break

    return results

A few practical notes on pagination:

Webhook JSON payloads from Follow Up Boss

Webhooks deliver event data to your endpoint as an HTTP POST with a JSON body the moment something changes in FUB — a contact is created, a stage transitions, a note is added. This is the right pattern for any integration that needs to react in near real-time rather than polling.

A personCreated webhook payload looks similar to the single-resource contact GET response, wrapped in an event envelope:

{
  "event": "personCreated",
  "eventId": "evt_abc123",
  "uri": "https://api.followupboss.com/v1/people/12345",
  "data": {
    "id": 12345,
    "firstName": "Jordan",
    "lastName": "Rivera",
    "stage": "New Lead",
    "source": "Zillow",
    "created": "2026-06-26T10:00:00Z"
  }
}

Steps for reliable webhook processing:

  1. Register the webhook via POST /v1/webhooks with your url, event type, and optionally a secret for signature verification.
  2. Respond with 200 immediately. FUB expects a response within a few seconds. If you do not respond in time, FUB will retry delivery. Accept the payload, enqueue it to a background job, and return 200 before doing any processing.
  3. Verify the signature if you configured a secret — compare the HMAC digest in the request header against your own computation of the payload body.
  4. Parse data the same way you parse a single-resource contact response — same field names, same types.
  5. Handle duplicates using eventId. Webhook delivery is at-least-once; occasional duplicates are normal. Store processed event IDs and skip duplicates.

Parsing custom fields in the API response

Custom fields in Follow Up Boss are extensible properties you define in your account. When you retrieve a contact via the API, custom field values appear as top-level properties on the contact object, using the field's configured name as the key.

For example, if you have a custom field named customBuyerTimeline, its value appears directly on the contact JSON at the root level:

{
  "id": 12345,
  "firstName": "Jordan",
  "customBuyerTimeline": "3-6 months",
  "customBudgetRange": "600000-800000"
}

To write a custom field value, include it by name in your POST or PUT body. To discover what custom fields exist in an account, call GET /v1/customFields — this returns the field definitions including name, type, and available choices for dropdown fields.

Ace Score fields in the FUB API response

Follow Up Ace writes AI-generated scoring data back to FUB as custom fields. If Follow Up Ace is connected to an account, these fields appear in the contact JSON response alongside any other custom fields. They are created automatically by Follow Up Ace and populated via webhook-driven analysis.

The pre-consolidation free Ace Score fields (retired June 2026 — see the update note above; the current free set is customAceWinScore + customAceChurnRisk):

Field name in API Type Description
customAceScore number (0–100) Lead engagement score, updated live via webhooks
customAceTier string (dropdown) Hot, Warm, Cool, Cold, or Dormant — banded from the score
customAceStatus string (dropdown) Pipeline status: New, Contacted, Engaged, Active Client, Closed, Nurturing, or Dormant
customAceResponseTime number Minutes to first agent response after lead creation
customAceVelocityScore number (0–100) Engagement velocity derived from event volume over 7-day and 30-day windows
customAceDaysSinceInbound number Days since this contact last sent an inbound message
customAcePreferredChannel string (dropdown) sms, email, or call — the channel the contact most recently engages on

Paid Ace Trove accounts also receive deeper intelligence fields including customAceLeadType, customAcePropertyProfile, customAceSearchArea, customAceBuyerReadiness, customAceLeadSummary, customAceNextAction, and the seller propensity tier field (customAceSellerTier). The underlying 0–100 Seller Score itself lives in the Seller Radar view rather than a FUB custom field.

Reading them in JavaScript is no different from reading any other field:

// After fetching a contact object from GET /v1/people/{id}:
const contact = await fetchContact(id);

const aceScore   = contact.customAceScore;         // number, e.g. 74
const aceTier    = contact.customAceTier;           // string, e.g. "Warm"
const aceDays    = contact.customAceDaysSinceInbound; // number, e.g. 3
const aceChannel = contact.customAcePreferredChannel; // string, e.g. "sms"

// Null-safe access if the field may not be set yet:
const tier = contact.customAceTier ?? 'Unknown';

Using an AI connector instead of raw JSON parsing

If the goal is natural-language access to contact data rather than a deterministic data pipeline, parsing raw JSON yourself is the wrong level of abstraction. Follow Up Ace exposes a Model Context Protocol (MCP) connector at https://followupace.com/mcp that allows an AI assistant like Claude to search contacts, read scores, log notes, and trigger actions through conversation — no JSON parsing required on your end.

The Agentic connector sits on top of the same FUB API endpoints described in this article; it just handles authentication, pagination, and field mapping for you. For teams that want both layers — a reliable ETL pipeline for data sync and a conversational interface for ad-hoc queries — the two approaches complement each other well.

Common parsing pitfalls and how to avoid them

Further reading

Try Follow Up Ace in your Follow Up Boss

Free to start, no sales call. Connect Follow Up Boss in one click and Ace works inside your CRM.

Get Started Free