Skip to main content

Setting up the Fathom integration

Automatically sync Fathom call intelligence data into Planhat as Conversations via a Custom Automation

Carly Hammond avatar
Written by Carly Hammond
Updated this week

Summary

  • Data you can sync

    • Sync Fathom AI call summaries and selected call data into Planhat as Conversations

  • Sync direction

    • One direction: from Fathom to Planhat

  • Sync frequency

    • Near instant, through webhooks

Who is this article for?

  • Anyone interested in syncing Fathom data to Planhat

Article contents


Introduction

The Planhat integration with Fathom enables automatic logging of AI-enriched call data, synced in as Conversations mapped to the relevant Company and End User(s) within Planhat.

This streamlines Customer Success and Sales processes:

  • It removes the need for manual note-taking and analysis, saving you time

  • It enables you and your colleagues to get a full 360-degree view of your customers/prospects, as your meeting data can be viewed and analyzed alongside all other data types in Planhat

In this article we show you what the Fathom integration looks like, describe the advantages it brings you, and explain how it works and how to set it up.


What is the Fathom integration?

The Fathom integration is a "light" integration. It's actually a Custom Automation that you can build in the App Center of your Planhat tenant - we give instructions below, and you can speak with your Planhat TAM if you need additional support.

Once configured, Fathom data will be synced into Planhat and saved on the Conversation model, and linked to the appropriate Company and End User(s).

More specifically, when a meeting is processed in Fathom, this is sent into Planhat via a webhook, and (via a Custom Automation) Planhat automatically saves this as a new Conversation record as follows:

  • The subject is set (as received from the Fathom webhook, or "Fathom Meeting" as a fallback)

  • The Conversation Type is set to a specific value as defined when the integration is set up - "Demo" in the screenshot below

  • The "Team Members" field is populated with the Planhat Users (you and your colleagues) who were involved in the meeting

  • The "Involved Contacts" field is populated with the relevant Planhat End Users (prospects or customers)

  • The Fathom URL is added to the "Call Recording" field (a custom field)

  • The "Description" is populated with a meeting summary, with the following sections:

    • "Summary"

    • "Action Items"

    • "Transcript" (truncated if necessary)

Conversation records created via the Fathom integration will look similar to this:

(You can click the image above to view it enlarged. The grey boxes are where customer information has been hidden for the image.)

πŸ“Œ Definitions

  • CRM data in Planhat is structured into "models", similar to the "objects" you may be familiar with from other tools

    • "Company" is the model representing businesses/organizations that are your prospects or customers

    • "End User" is the model representing individual people at those Companies (sometimes called Contacts)

    • "User" is the model representing users of Planhat - you and your teammates (sometimes called Team Members)

    • "Conversation" is the model representing communication ("logged activities"), including emails, tickets, calls and meetings etc.

  • "Records" correspond to data within those models - e.g. for the Company model, a record could be Apple; for the End User model, a record could be Becky Booth; and for the Conversation model, a record could be a Kick-Off Call with Company X


Why use the Fathom integration?

The Fathom integration has many key features and benefits, including:

  • Fathom gives you AI-powered meeting analysis - you save time as you don't need to manually write up your own detailed notes after every meeting and extract action points etc.

  • Meeting data is automatically synced into Planhat (your CRM or CSP) - you do not need to manually copy in notes from Fathom

  • You have near-instant visibility into what was discussed on customer/prospect meetings/calls

  • In Planhat, all your different types of customer/prospect data is centralized together in one place, rather than being split in multiple separate tools, so you have a complete understanding and can act appropriately

  • In addition to providing the call notes and action points etc. for the Planhat user who was on the call, other team members (e.g. Support) can also view the details to gain context for when they are working with this customer/prospect


How the sync works

To summarize:

  • Fathom sends a webhook when a call is processed, and this is received by a Custom Automation in Planhat

  • The Automation parses the payload to extract the URL, summary, transcript, action items and attendees

  • It transforms the payload into Planhat's Conversation format - it sets the "subject", "externalId", "users" (internal), "endusers" (external), "companyId" (looked up by first external attendee), and a rich "description" (summary + action items + transcript).

  • The final step of the Automation sends the details to Planhat's API to save them as a Conversation record in your Planhat tenant

Note that Fathom already includes all required details in the webhook payload - no API call to Fathom is needed.


How to set up the Fathom integration

You should be able to set this up yourself by following the instructions below, but if you need additional help or guidance, feel free to reach out to your TAM (or our Support team).

Preliminary steps

Before you build the Automation, there are a couple of things to set up in your Planhat tenant:

  • Custom Conversation Type

    • Each Fathom meeting is saved as a Conversation record in Planhat. Each Conversation record has a corresponding Conversation Type

    • You can create your own custom Conversation Types in Planhat

    • In the Fathom Automation as shown in this article, we use a custom Conversation Type called "Demo" - so you should either create this following the instructions in the article linked to above (assuming you don't already have this particular Conversation Type); or if you want to use a different Conversation Type, you can do so, but note that this name is referenced in the Automation so you will need to take that into account

  • Custom Field

    • Most of the fields on the Conversation model that we use in this Automation are system (i.e. standard/default) fields, but we save the Fathom call link in a custom field called "Call Recording"

    • Again, assuming you want to copy the setup described in this article, you should create a field (type: URL) on the Conversation model called "Call Recording" (following the general instructions here)

    • If you use a different field - with a different name - then make a note of it when you're building the Automation, as it's referenced

Fathom webhook

The Automation in Planhat is triggered when it receives an incoming webhook from Fathom. You need to set up the webhook in Fathom:

  1. Go to Settings β†’ Integrations β†’ Webhooks in Fathom

  2. Add Webhook: "New meeting content ready"

  3. Paste in the Planhat webhook URL*

  4. Save

*This is a URL unique to your Automation. To get it, you need to start building the Automation in Planhat (instructions below), and save it. Then, when you open it and select the incoming webhook trigger, you will see a "Copy URL" button, as shown in this screenshot:

You can read more about building Automations with webhooks (more generally) here, and see the instructions specifically for the Fathom Custom Automation below.

Custom Automation

Within Planhat, the Fathom "integration" is actually a Custom Automation, which you can build in your Planhat tenant, within the App Center. You can read about setting up Custom Automations generally here, and we'll link to more specific Custom Automation articles below. In this article, we will focus specifically on the details of the Fathom Automation.

Your overall Automation will look similar to this:

πŸ“Œ Important to note

Each Custom Automation step (so that's after the trigger) is automatically assigned a random name such as "s-HNn" (as you can see in the final step above). You can rename each step (e.g. to "Step 1"), as described here. This renaming can make things clearer in the UI. Note that if you then refer to that step in a replacement code in a subsequent step, you need to use its actual current step name, whether that's a random code name or edited name.

To summarize the process, shown in the screenshot above:

Let's look at each of these steps in further detail.

Trigger - incoming webhook

The trigger for this Automation is an incoming webhook from Fathom.

It's set to "anything" (as shown), but it's connected to Fathom by clicking "Copy URL" (which gives a unique URL for this Automation) and pasting that into Fathom, as we mentioned above.

First and second steps - functions

The first two steps are both "Execute Function" (also called "Function Execution") steps, which you can read more about here.

In this Automation, these steps:

  • Extract the meeting title, URL, summary, transcript, action items, and attendees

  • Map internal attendees to "users" and external attendees to "endusers"

  • Look up the Planhat "companyId" via the first external attendee's email address

  • Build the HTML description: summary, action items, and transcript (with size clipping)

You can copy and paste the following into your steps:

First step

var webhookData = <<update>>;

return {
meetingUrl:
webhookData?.url ||
webhookData?.share_url ||
webhookData?.meeting_url ||
null,
createdAt: webhookData?.created_at || null,
recordedBy: webhookData?.recorded_by?.email || null,
transcript: webhookData?.transcript || null,
summary: webhookData?.default_summary || null,
actionItems: webhookData?.action_items || null,
attendees: webhookData?.calendar_invitees || null,
meetingTitle: webhookData?.meeting_title || null,
};

Second step

const data = <<Step 1>>;

// single meeting object now (still tolerate array just in case)
const m = Array.isArray(data?.items) ? data.items[0] : data;
if (!m) return "No meeting";

// ---- Title / URL ----
const rawTitle =
m?.meetingTitle ||
m?.meeting_title ||
m?.title ||
"";

const title = (typeof rawTitle === "string" && rawTitle.trim()) || "Fathom Meeting";

const url =
m?.url ||
m?.share_url ||
m?.meetingUrl || // Step 1 field
null;

// ---- Team Members (Planhat 'users') ----
let users = [];
if (m?.recorded_by?.email) {
users.push({ email: m.recorded_by.email, name: m.recorded_by.name || "" });
}
// dedupe users by email
users = users.filter(
(u, i, arr) => u?.email && i === arr.findIndex(v => v.email === u.email)
);

// ---- End Users (externals) ----
const invitees =
Array.isArray(m?.attendees) ? m.attendees :
Array.isArray(m?.calendar_invitees) ? m.calendar_invitees : [];

const externalInvitees = invitees.filter(i => i?.email && i.is_external);
let endusers = externalInvitees.map(i => ({ email: i.email }));
// dedupe endusers by email
endusers = endusers.filter(
(e, i, arr) => i === arr.findIndex(v => v.email === e.email)
);

// ---- Company lookup (first external) ----
let companyId = null;
if (externalInvitees.length) {
const firstExt = externalInvitees[0].email;
const u = await ph.models.endUsers.getAll({ email: firstExt });
companyId = u.length ? u[0].companyId : null;
}

// ---- Summary ----
const cleanMdToHtml = (md) =>
(md || "")
.replace(/^#{1,6}\s*/gm, "")
.replace(/^\s*-\s+/gm, "β€’ ")
.replace(/\*\*(.*?)\*\*/g, "<strong>$1</strong>")
.replace(/__(.*?)__/g, "<strong>$1</strong>")
.replace(/\n/g, "<br>");

const summaryHtml = cleanMdToHtml(
m?.default_summary?.markdown_formatted ||
m?.summary?.markdown_formatted ||
""
);

// ---- Action Items ----
const actionItemsHtml = (m?.action_items || [])
.map(a => `β€’ ${a?.description || a}`)
.join("<br>");

// ---- Transcript ----
const transcriptArr = Array.isArray(m?.transcript) ? m.transcript : [];
const transcriptHtml = transcriptArr
.map(t => `<strong>${t?.speaker?.display_name || "Speaker"}</strong>: ${t?.text || ""}`)
.join("<br>");

const clip = (s, max = 25000) =>
(s && s.length > max ? s.slice(0, max) + "…(truncated)" : (s || ""));

const description = `
<strong>Summary:</strong><br>${summaryHtml || "(none)"}<br><br>
<strong>Action Items:</strong><br>${actionItemsHtml || "(none)"}<br><br>
<strong>Transcript included:</strong> ${transcriptArr.length ? "Yes" : "No"}<br><br>
<strong>Transcript:</strong><br>${clip(transcriptHtml)}
`;

// If no URL, fall back to title so externalId isn’t empty
return {
url,
subject: title,
externalId: url || title,
endusers,
companyId,
users,
description
};

Third step - "call a webhook"

The final step of the Automation calls a webhook to communicate with the Planhat API and create/populate the Conversation record to represent this meeting in Planhat.

You can see the setup in the screenshot above.

The full URL in the screenshot is https://api.planhatdemo.com/conversations - but note that this is because it has been built in a demo Planhat tenant, with a URL https://ws.planhatdemo.com/ - you should adjust this URL to suit that of your own Planhat tenant.

The "Body" of this step is as follows, so you can copy and paste this.*

{
"subject": "<<Step 2.subject>>",
"type": "Demo",
"externalId": "<<Step 2.externalId>>",
"companyId": "<<Step 2.companyId>>",
"endusers": "<<Step 2.endusers>>",
"users": "<<Step 2.users>>",
"custom": {
"Call Recording": "<<Step 2.url>>"
},
"description": "<<Step 2.description>>"
}

*Notes:

  • The text above uses replacement codes to refer to the previous Function step, so this needs to match the name of the preceding step in your Automation - it may be Step 2 if you renamed your step like in our example, but if your preceding step is called something else (like "S-WRp"), then you will need to use that name in place of Step 2 here

  • The text above refers to a custom field on the Conversation model called "Call Recording", which we mentioned earlier. If you don't have this specific field, and are using a different one, make sure you replace the reference so it states your desired field

  • The text above refers to a Conversation Type called "Demo", which we mentioned earlier. If you don't have this specific Conversation Type, and are using a different one, make sure you replace the reference so it states your desired Conversation Type

  • Setting the Conversation External ID (as included above) ensures there aren't duplicate Conversations

Testing

Once you've built your Automation, we recommend that you test it to confirm that everything is set up correctly. To do this, follow these simple steps:

  1. Run a short Fathom test meeting

    • Include at least one external attendee (an End User belonging to a Company in your Planhat tenant) so the Company lookup can work

  2. End the call - the webhook should fire within about a minute

  3. Check that the Conversation record has been created in Planhat, with all the relevant fields filled in. (You may need to refresh your browser window)

Troubleshooting

If you see a "CompanyId missing" error, this could be caused by there being no external attendees, or an external attendee email address not being found in Planhat.

Please be aware that long transcripts may be clipped, to fit the size limit for Conversation records.

Did this answer your question?