> ## Documentation Index
> Fetch the complete documentation index at: https://rollout.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Have a Follow Up Boss Integration? Start Here

### Add Every Real Estate CRM Integration in \< 1 Hour (While Keeping Your Existing FUB Code)

**Scenario:** Your product currently talks to **Follow Up Boss (FUB)** *directly* via the FUB API. You want to add other CRMs (e.g., **BoldTrail, Lofty, Brivity, CINC, Sierra Interactive, Real Geeks, HubSpot, HighLevel**, etc.) without refactoring your data model.

**Outcome:** In under an hour, Connect more CRMs using **Rollout**. Keep your FUB integration as‑is. Rollout normalizes the rest; you add a thin adapter that maps Rollout records to your existing FUB‑shaped objects and routes webhook events into your current pipelines.

### What You’ll Build

1. **Credential connect UI** to add non‑FUB CRMs.

2. **Routing switch** that calls Rollout for non‑FUB tenants.

3. **One webhook endpoint** for Rollout events that feeds your existing FUB upsert logic.

Keep using native FUB API for FUB customers. Use Rollout only for the *other* CRMs.

### Prereqs (5–10 min)

* Create a Rollout app (Client ID/Secret). Add:

  * `ROLLOUT_CLIENT_ID`, `ROLLOUT_CLIENT_SECRET`

  * `ROLLOUT_WEBHOOK_SECRET`

* Small table for Rollout connections: `tenant_id`, `connection_id`, `category='crm'`, `provider`, `status`.

### Step 1: Drop in the Connect UI (5–10 min)

Render Rollout’s credential manager on your Integrations page so customers can add CRMs beyond FUB. People sync automatically where supported. This example also enables notes and tasks; choose the optional data types your existing FUB integration uses. See [Choose what data to sync](/docs/advanced-guides/controlling-which-records-sync-with-rollout) for other types and existing connections.

```typescript theme={null}
// IntegrationsPage.jsx
<CredentialsManager
  apiCategories={{ crm: true }}
  entitiesToSync={{ notes: true, tasks: true }}
  onCredentialAdded={({ id }) => saveConnection({ tenantId, connectionId: id, category: 'crm' })}
/>
```

* Store `connection_id` when the OAuth/API‑key flow finishes.

### Step 2: Update your FUB Code for Reads/Writes (10–15 min)

Keep your **FUB** client for FUB tenants. For *other CRMs*, call **Rollout** with the **same FUB‑shaped payloads** and responses.

```typescript theme={null}
// peopleService.ts (minimal, no client wrapper)
import fetch from 'node-fetch';

async function rolloutHeaders(tenantId: string, credentialId: string) {
  const authToken = await getRolloutToken(tenantId); // server-side per Rollout docs
  return {
    Authorization: `Bearer ${authToken}`,
    'x-rollout-credential-id': credentialId,
    'Content-Type': 'application/json'
  };
}

export async function listPeople(tenantId: string) {
  const cred = await getActiveCrmCredential(tenantId);
  if (cred?.provider === 'fub') return fubClient.listPeople();
  const res = await fetch('https://crm.universal.rollout.com/api/people', {
    headers: await rolloutHeaders(tenantId, cred.credentialId)
  });
  const data = await res.json();
  if (!res.ok) throw new Error(data.errorMessage || data.error || 'Failed to fetch people');
  return data.items; // same shape you already use
}

export async function createPerson(tenantId: string, fubPayload: any) {
  const cred = await getActiveCrmCredential(tenantId);
  if (cred?.provider === 'fub') return fubClient.createPerson(fubPayload);
  const res = await fetch('https://crm.universal.rollout.com/api/people', {
    method: 'POST',
    headers: await rolloutHeaders(tenantId, cred.credentialId),
    body: JSON.stringify(fubPayload)
  });
  const data = await res.json();
  if (!res.ok) throw new Error(data.errorMessage || data.error || 'Failed to create person');
  return data; // same shape
}
```

Tip: Keep your domain types untouched. Just pick the right client based on the active connection.

### Step 3: One Webhook for All Non‑FUB CRMs (10 min)

Subscribe connections to Rollout webhooks. Verify HMAC, fetch via `uri`, then run your existing FUB upsert.

```typescript theme={null}
// webhooks/rollout.ts
app.post('/webhooks/rollout', verifyHmac(ROLLOUT_WEBHOOK_SECRET), async (req, res) => {
  const { event, uri } = req.body; // e.g., peopleCreated, peopleUpdated, peopleDeleted
  // Identify the tenant & related credential for this webhook (use your own mapping)
  const { tenantId, credentialId } = await resolveTenantAndCredential(req);

  const resp = await fetch(uri.startsWith('http') ? uri : `https://crm.universal.rollout.com${uri}`, {
    headers: await rolloutHeaders(tenantId, credentialId)
  });
  const data = await resp.json();
  if (!resp.ok) throw new Error(data.errorMessage || data.error || 'Fetch via webhook URI failed');

  for (const item of data.items) {
    await upsertPerson(item); // same handler you use for FUB
  }
  res.sendStatus(200);
});
```

Event names and payloads match your FUB expectations for CRM entities.

### Optional: Extra Entities (5 min)

If you already support FUB **tasks/notes/emails/calls**, include the corresponding `tasks`, `notes`, `emailMessages`, or `calls` keys in `entitiesToSync`, where the connector supports them. Set this before users connect, and [update existing connections](/docs/advanced-guides/controlling-which-records-sync-with-rollout#update-an-existing-connection) separately. Then reuse your existing code paths for the supported shapes and events.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.