feat(tools): add Fathom AI Notetaker integration (#3531)

* feat(fathom): add Fathom AI Notetaker integration

* fix(fathom): address PR review feedback

- Add response.ok checks to all 5 tool transformResponse functions
- Fix include_summary default to respect explicit false (check undefined)
- Add externalId validation before URL interpolation in webhook deletion

* fix(fathom): address second round PR review feedback

- Remove redundant 204 status check in deleteFathomWebhook (204 is ok)
- Use consistent undefined-guard pattern for all include flags
- Add .catch() fallback on webhook creation JSON parse
- Change recording_id default from 0 to null to avoid misleading sentinel

* fix(fathom): add missing crm_matches to list_meetings transform and fix action_items type

- Add crm_matches pass-through in list_meetings transform (was silently dropped)
- Fix action_items type to match API schema (description, user_generated, completed, etc.)
- Add crm_matches type with contacts, companies, deals, error fields

* fix(fathom): guard against undefined webhook id on creation success

* fix(fathom): add type to nested trigger outputs and fix boolean coercion

- Add type: 'object' to recorded_by and default_summary trigger outputs
- Use val === true || val === 'true' pattern for include flag coercion
  to safely handle both boolean and string values from providerConfig

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Lakee Sivaraya <71339072+lakeesiv@users.noreply.github.com>
Co-authored-by: Vikhyath Mondreti <vikhyath@simstudio.ai>
Co-authored-by: Vikhyath Mondreti <vikhyathvikku@gmail.com>
This commit is contained in:
Waleed
2026-03-12 11:00:07 -07:00
committed by GitHub
parent 9295499405
commit 97f78c60b4
21 changed files with 1629 additions and 0 deletions

View File

@@ -1979,6 +1979,24 @@ export function ElevenLabsIcon(props: SVGProps<SVGSVGElement>) {
)
}
export function FathomIcon(props: SVGProps<SVGSVGElement>) {
return (
<svg {...props} xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1000 1000' fill='none'>
<path
d='M0,668.7v205.78c0,53.97,34.24,102.88,85.8,119.08,87.48,27.49,167.88-36.99,167.88-120.22v-77.45L0,668.7Z'
fill='#007299'
/>
<path
d='M873.72,626.07c-19.05,0-38.38-4.3-56.58-13.38L72.78,241.43C11.15,210.69-17.51,136.6,11.18,74.05,41.2,8.59,119.26-18.53,183.23,13.38l744.25,371.21c62.45,31.15,91,109.08,59.79,171.43-22.22,44.38-67.02,70.05-113.55,70.05Z'
fill='#00beff'
/>
<path
d='M500.09,813.66c-19.05,0-38.38-4.3-56.58-13.38l-370.72-184.9c-61.63-30.74-90.29-104.82-61.61-167.37,30.02-65.46,108.08-92.59,172.06-60.68l370.62,184.85c62.45,31.15,91,109.08,59.79,171.43-22.22,44.38-67.02,70.05-113.55,70.05Z'
fill='#00beff'
/>
</svg>
)
}
export function LinkupIcon(props: SVGProps<SVGSVGElement>) {
return (
<svg {...props} xmlns='http://www.w3.org/2000/svg' viewBox='0 0 154 107' fill='none'>

View File

@@ -43,6 +43,7 @@ import {
EvernoteIcon,
ExaAIIcon,
EyeIcon,
FathomIcon,
FirecrawlIcon,
FirefliesIcon,
GammaIcon,
@@ -206,6 +207,7 @@ export const blockTypeToIconMap: Record<string, IconComponent> = {
enrich: EnrichSoIcon,
evernote: EvernoteIcon,
exa: ExaAIIcon,
fathom: FathomIcon,
file_v3: DocumentIcon,
firecrawl: FirecrawlIcon,
fireflies_v2: FirefliesIcon,

View File

@@ -0,0 +1,135 @@
---
title: Fathom
description: Access meeting recordings, transcripts, and summaries
---
import { BlockInfoCard } from "@/components/ui/block-info-card"
<BlockInfoCard
type="fathom"
color="#181C1E"
/>
## Usage Instructions
Integrate Fathom AI Notetaker into your workflow. List meetings, get transcripts and summaries, and manage team members and teams. Can also trigger workflows when new meeting content is ready.
## Tools
### `fathom_list_meetings`
List recent meetings recorded by the user or shared to their team.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Fathom API Key |
| `includeSummary` | string | No | Include meeting summary \(true/false\) |
| `includeTranscript` | string | No | Include meeting transcript \(true/false\) |
| `includeActionItems` | string | No | Include action items \(true/false\) |
| `includeCrmMatches` | string | No | Include linked CRM matches \(true/false\) |
| `createdAfter` | string | No | Filter meetings created after this ISO 8601 timestamp |
| `createdBefore` | string | No | Filter meetings created before this ISO 8601 timestamp |
| `recordedBy` | string | No | Filter by recorder email address |
| `teams` | string | No | Filter by team name |
| `cursor` | string | No | Pagination cursor from a previous response |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `meetings` | array | List of meetings |
| ↳ `title` | string | Meeting title |
| ↳ `recording_id` | number | Unique recording ID |
| ↳ `url` | string | URL to view the meeting |
| ↳ `share_url` | string | Shareable URL |
| ↳ `created_at` | string | Creation timestamp |
| ↳ `transcript_language` | string | Transcript language |
| `next_cursor` | string | Pagination cursor for next page |
### `fathom_get_summary`
Get the call summary for a specific meeting recording.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Fathom API Key |
| `recordingId` | string | Yes | The recording ID of the meeting |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `template_name` | string | Name of the summary template used |
| `markdown_formatted` | string | Markdown-formatted summary text |
### `fathom_get_transcript`
Get the full transcript for a specific meeting recording.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Fathom API Key |
| `recordingId` | string | Yes | The recording ID of the meeting |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `transcript` | array | Array of transcript entries with speaker, text, and timestamp |
| ↳ `speaker` | object | Speaker information |
| ↳ `display_name` | string | Speaker display name |
| ↳ `matched_calendar_invitee_email` | string | Matched calendar invitee email |
| ↳ `text` | string | Transcript text |
| ↳ `timestamp` | string | Timestamp \(HH:MM:SS\) |
### `fathom_list_team_members`
List team members in your Fathom organization.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Fathom API Key |
| `teams` | string | No | Team name to filter by |
| `cursor` | string | No | Pagination cursor from a previous response |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `members` | array | List of team members |
| ↳ `name` | string | Team member name |
| ↳ `email` | string | Team member email |
| ↳ `created_at` | string | Date the member was added |
| `next_cursor` | string | Pagination cursor for next page |
### `fathom_list_teams`
List teams in your Fathom organization.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Fathom API Key |
| `cursor` | string | No | Pagination cursor from a previous response |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `teams` | array | List of teams |
| ↳ `name` | string | Team name |
| ↳ `created_at` | string | Date the team was created |
| `next_cursor` | string | Pagination cursor for next page |

View File

@@ -37,6 +37,7 @@
"enrich",
"evernote",
"exa",
"fathom",
"file",
"firecrawl",
"fireflies",

View File

@@ -0,0 +1,211 @@
import { FathomIcon } from '@/components/icons'
import { AuthMode, type BlockConfig } from '@/blocks/types'
import type { FathomResponse } from '@/tools/fathom/types'
import { getTrigger } from '@/triggers'
import { fathomTriggerOptions } from '@/triggers/fathom/utils'
export const FathomBlock: BlockConfig<FathomResponse> = {
type: 'fathom',
name: 'Fathom',
description: 'Access meeting recordings, transcripts, and summaries',
authMode: AuthMode.ApiKey,
triggerAllowed: true,
longDescription:
'Integrate Fathom AI Notetaker into your workflow. List meetings, get transcripts and summaries, and manage team members and teams. Can also trigger workflows when new meeting content is ready.',
docsLink: 'https://docs.sim.ai/tools/fathom',
category: 'tools',
bgColor: '#181C1E',
icon: FathomIcon,
subBlocks: [
{
id: 'operation',
title: 'Operation',
type: 'dropdown',
options: [
{ label: 'List Meetings', id: 'fathom_list_meetings' },
{ label: 'Get Summary', id: 'fathom_get_summary' },
{ label: 'Get Transcript', id: 'fathom_get_transcript' },
{ label: 'List Team Members', id: 'fathom_list_team_members' },
{ label: 'List Teams', id: 'fathom_list_teams' },
],
value: () => 'fathom_list_meetings',
},
{
id: 'recordingId',
title: 'Recording ID',
type: 'short-input',
required: { field: 'operation', value: ['fathom_get_summary', 'fathom_get_transcript'] },
placeholder: 'Enter the recording ID',
condition: { field: 'operation', value: ['fathom_get_summary', 'fathom_get_transcript'] },
},
{
id: 'includeSummary',
title: 'Include Summary',
type: 'dropdown',
options: [
{ label: 'No', id: 'false' },
{ label: 'Yes', id: 'true' },
],
value: () => 'false',
condition: { field: 'operation', value: 'fathom_list_meetings' },
},
{
id: 'includeTranscript',
title: 'Include Transcript',
type: 'dropdown',
options: [
{ label: 'No', id: 'false' },
{ label: 'Yes', id: 'true' },
],
value: () => 'false',
condition: { field: 'operation', value: 'fathom_list_meetings' },
},
{
id: 'includeActionItems',
title: 'Include Action Items',
type: 'dropdown',
options: [
{ label: 'No', id: 'false' },
{ label: 'Yes', id: 'true' },
],
value: () => 'false',
condition: { field: 'operation', value: 'fathom_list_meetings' },
},
{
id: 'includeCrmMatches',
title: 'Include CRM Matches',
type: 'dropdown',
options: [
{ label: 'No', id: 'false' },
{ label: 'Yes', id: 'true' },
],
value: () => 'false',
condition: { field: 'operation', value: 'fathom_list_meetings' },
},
{
id: 'createdAfter',
title: 'Created After',
type: 'short-input',
placeholder: 'ISO 8601 timestamp (e.g., 2025-01-01T00:00:00Z)',
condition: { field: 'operation', value: 'fathom_list_meetings' },
mode: 'advanced',
wandConfig: {
enabled: true,
prompt: 'Generate an ISO 8601 timestamp. Return ONLY the timestamp string.',
generationType: 'timestamp',
},
},
{
id: 'createdBefore',
title: 'Created Before',
type: 'short-input',
placeholder: 'ISO 8601 timestamp (e.g., 2025-12-31T23:59:59Z)',
condition: { field: 'operation', value: 'fathom_list_meetings' },
mode: 'advanced',
wandConfig: {
enabled: true,
prompt: 'Generate an ISO 8601 timestamp. Return ONLY the timestamp string.',
generationType: 'timestamp',
},
},
{
id: 'recordedBy',
title: 'Recorded By',
type: 'short-input',
placeholder: 'Filter by recorder email',
condition: { field: 'operation', value: 'fathom_list_meetings' },
mode: 'advanced',
},
{
id: 'teams',
title: 'Team',
type: 'short-input',
placeholder: 'Filter by team name',
condition: {
field: 'operation',
value: ['fathom_list_meetings', 'fathom_list_team_members'],
},
mode: 'advanced',
},
{
id: 'cursor',
title: 'Pagination Cursor',
type: 'short-input',
placeholder: 'Cursor from a previous response',
condition: {
field: 'operation',
value: ['fathom_list_meetings', 'fathom_list_team_members', 'fathom_list_teams'],
},
mode: 'advanced',
},
{
id: 'apiKey',
title: 'API Key',
type: 'short-input',
required: true,
placeholder: 'Enter your Fathom API key',
password: true,
},
{
id: 'selectedTriggerId',
title: 'Trigger Type',
type: 'dropdown',
mode: 'trigger',
options: fathomTriggerOptions,
value: () => 'fathom_new_meeting',
required: true,
},
...getTrigger('fathom_new_meeting').subBlocks,
...getTrigger('fathom_webhook').subBlocks,
],
tools: {
access: [
'fathom_list_meetings',
'fathom_get_summary',
'fathom_get_transcript',
'fathom_list_team_members',
'fathom_list_teams',
],
config: {
tool: (params) => {
return params.operation || 'fathom_list_meetings'
},
},
},
inputs: {
operation: { type: 'string', description: 'Operation to perform' },
apiKey: { type: 'string', description: 'Fathom API key' },
recordingId: { type: 'string', description: 'Recording ID for summary or transcript' },
includeSummary: { type: 'string', description: 'Include summary in meetings response' },
includeTranscript: { type: 'string', description: 'Include transcript in meetings response' },
includeActionItems: {
type: 'string',
description: 'Include action items in meetings response',
},
includeCrmMatches: {
type: 'string',
description: 'Include linked CRM matches in meetings response',
},
createdAfter: { type: 'string', description: 'Filter meetings created after this timestamp' },
createdBefore: {
type: 'string',
description: 'Filter meetings created before this timestamp',
},
recordedBy: { type: 'string', description: 'Filter by recorder email' },
teams: { type: 'string', description: 'Filter by team name' },
cursor: { type: 'string', description: 'Pagination cursor for next page' },
},
outputs: {
meetings: { type: 'json', description: 'List of meetings' },
template_name: { type: 'string', description: 'Summary template name' },
markdown_formatted: { type: 'string', description: 'Markdown-formatted summary' },
transcript: { type: 'json', description: 'Meeting transcript entries' },
members: { type: 'json', description: 'List of team members' },
teams: { type: 'json', description: 'List of teams' },
next_cursor: { type: 'string', description: 'Pagination cursor' },
},
triggers: {
enabled: true,
available: ['fathom_new_meeting', 'fathom_webhook'],
},
}

View File

@@ -40,6 +40,7 @@ import { EnrichBlock } from '@/blocks/blocks/enrich'
import { EvaluatorBlock } from '@/blocks/blocks/evaluator'
import { EvernoteBlock } from '@/blocks/blocks/evernote'
import { ExaBlock } from '@/blocks/blocks/exa'
import { FathomBlock } from '@/blocks/blocks/fathom'
import { FileBlock, FileV2Block, FileV3Block } from '@/blocks/blocks/file'
import { FirecrawlBlock } from '@/blocks/blocks/firecrawl'
import { FirefliesBlock, FirefliesV2Block } from '@/blocks/blocks/fireflies'
@@ -235,6 +236,7 @@ export const registry: Record<string, BlockConfig> = {
dynamodb: DynamoDBBlock,
elasticsearch: ElasticsearchBlock,
elevenlabs: ElevenLabsBlock,
fathom: FathomBlock,
enrich: EnrichBlock,
evernote: EvernoteBlock,
evaluator: EvaluatorBlock,

View File

@@ -1979,6 +1979,24 @@ export function ElevenLabsIcon(props: SVGProps<SVGSVGElement>) {
)
}
export function FathomIcon(props: SVGProps<SVGSVGElement>) {
return (
<svg {...props} xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1000 1000' fill='none'>
<path
d='M0,668.7v205.78c0,53.97,34.24,102.88,85.8,119.08,87.48,27.49,167.88-36.99,167.88-120.22v-77.45L0,668.7Z'
fill='#007299'
/>
<path
d='M873.72,626.07c-19.05,0-38.38-4.3-56.58-13.38L72.78,241.43C11.15,210.69-17.51,136.6,11.18,74.05,41.2,8.59,119.26-18.53,183.23,13.38l744.25,371.21c62.45,31.15,91,109.08,59.79,171.43-22.22,44.38-67.02,70.05-113.55,70.05Z'
fill='#00beff'
/>
<path
d='M500.09,813.66c-19.05,0-38.38-4.3-56.58-13.38l-370.72-184.9c-61.63-30.74-90.29-104.82-61.61-167.37,30.02-65.46,108.08-92.59,172.06-60.68l370.62,184.85c62.45,31.15,91,109.08,59.79,171.43-22.22,44.38-67.02,70.05-113.55,70.05Z'
fill='#00beff'
/>
</svg>
)
}
export function LinkupIcon(props: SVGProps<SVGSVGElement>) {
return (
<svg {...props} xmlns='http://www.w3.org/2000/svg' viewBox='0 0 154 107' fill='none'>

View File

@@ -17,6 +17,7 @@ const airtableLogger = createLogger('AirtableWebhook')
const typeformLogger = createLogger('TypeformWebhook')
const calendlyLogger = createLogger('CalendlyWebhook')
const grainLogger = createLogger('GrainWebhook')
const fathomLogger = createLogger('FathomWebhook')
const lemlistLogger = createLogger('LemlistWebhook')
const webflowLogger = createLogger('WebflowWebhook')
const attioLogger = createLogger('AttioWebhook')
@@ -792,6 +793,60 @@ export async function deleteGrainWebhook(webhook: any, requestId: string): Promi
}
}
/**
* Delete a Fathom webhook
* Don't fail webhook deletion if cleanup fails
*/
export async function deleteFathomWebhook(webhook: any, requestId: string): Promise<void> {
try {
const config = getProviderConfig(webhook)
const apiKey = config.apiKey as string | undefined
const externalId = config.externalId as string | undefined
if (!apiKey) {
fathomLogger.warn(
`[${requestId}] Missing apiKey for Fathom webhook deletion ${webhook.id}, skipping cleanup`
)
return
}
if (!externalId) {
fathomLogger.warn(
`[${requestId}] Missing externalId for Fathom webhook deletion ${webhook.id}, skipping cleanup`
)
return
}
const idValidation = validateAlphanumericId(externalId, 'Fathom webhook ID', 100)
if (!idValidation.isValid) {
fathomLogger.warn(
`[${requestId}] Invalid externalId format for Fathom webhook deletion ${webhook.id}, skipping cleanup`
)
return
}
const fathomApiUrl = `https://api.fathom.ai/external/v1/webhooks/${externalId}`
const fathomResponse = await fetch(fathomApiUrl, {
method: 'DELETE',
headers: {
'X-Api-Key': apiKey,
'Content-Type': 'application/json',
},
})
if (!fathomResponse.ok && fathomResponse.status !== 404) {
fathomLogger.warn(
`[${requestId}] Failed to delete Fathom webhook (non-fatal): ${fathomResponse.status}`
)
} else {
fathomLogger.info(`[${requestId}] Successfully deleted Fathom webhook ${externalId}`)
}
} catch (error) {
fathomLogger.warn(`[${requestId}] Error deleting Fathom webhook (non-fatal)`, error)
}
}
/**
* Delete a Lemlist webhook
* Don't fail webhook deletion if cleanup fails
@@ -1314,6 +1369,116 @@ export async function createGrainWebhookSubscription(
}
}
export async function createFathomWebhookSubscription(
_request: NextRequest,
webhookData: any,
requestId: string
): Promise<{ id: string } | undefined> {
try {
const { path, providerConfig } = webhookData
const {
apiKey,
triggerId,
triggeredFor,
includeSummary,
includeTranscript,
includeActionItems,
includeCrmMatches,
} = providerConfig || {}
if (!apiKey) {
fathomLogger.warn(`[${requestId}] Missing apiKey for Fathom webhook creation.`, {
webhookId: webhookData.id,
})
throw new Error(
'Fathom API Key is required. Please provide your API key in the trigger configuration.'
)
}
const notificationUrl = `${getBaseUrl()}/api/webhooks/trigger/${path}`
const triggeredForValue = triggeredFor || 'my_recordings'
const toBool = (val: unknown, fallback: boolean): boolean => {
if (val === undefined) return fallback
return val === true || val === 'true'
}
const requestBody: Record<string, any> = {
destination_url: notificationUrl,
triggered_for: [triggeredForValue],
include_summary: toBool(includeSummary, true),
include_transcript: toBool(includeTranscript, false),
include_action_items: toBool(includeActionItems, false),
include_crm_matches: toBool(includeCrmMatches, false),
}
fathomLogger.info(`[${requestId}] Creating Fathom webhook`, {
triggerId,
triggeredFor: triggeredForValue,
webhookId: webhookData.id,
})
const fathomResponse = await fetch('https://api.fathom.ai/external/v1/webhooks', {
method: 'POST',
headers: {
'X-Api-Key': apiKey,
'Content-Type': 'application/json',
},
body: JSON.stringify(requestBody),
})
const responseBody = await fathomResponse.json().catch(() => ({}))
if (!fathomResponse.ok) {
const errorMessage =
(responseBody as Record<string, string>).message ||
(responseBody as Record<string, string>).error ||
'Unknown Fathom API error'
fathomLogger.error(
`[${requestId}] Failed to create webhook in Fathom for webhook ${webhookData.id}. Status: ${fathomResponse.status}`,
{ message: errorMessage, response: responseBody }
)
let userFriendlyMessage = 'Failed to create webhook subscription in Fathom'
if (fathomResponse.status === 401) {
userFriendlyMessage = 'Invalid Fathom API Key. Please verify your key is correct.'
} else if (fathomResponse.status === 400) {
userFriendlyMessage = `Fathom error: ${errorMessage}`
} else if (errorMessage && errorMessage !== 'Unknown Fathom API error') {
userFriendlyMessage = `Fathom error: ${errorMessage}`
}
throw new Error(userFriendlyMessage)
}
if (!responseBody.id) {
fathomLogger.error(
`[${requestId}] Fathom webhook creation returned success but no webhook ID for ${webhookData.id}.`
)
throw new Error('Fathom webhook created but no ID returned. Please try again.')
}
fathomLogger.info(
`[${requestId}] Successfully created webhook in Fathom for webhook ${webhookData.id}.`,
{
fathomWebhookId: responseBody.id,
}
)
return { id: responseBody.id }
} catch (error: any) {
fathomLogger.error(
`[${requestId}] Exception during Fathom webhook creation for webhook ${webhookData.id}.`,
{
message: error.message,
stack: error.stack,
}
)
throw error
}
}
export async function createLemlistWebhookSubscription(
webhookData: any,
requestId: string
@@ -1811,6 +1976,7 @@ const PROVIDERS_WITH_EXTERNAL_SUBSCRIPTIONS = new Set([
'airtable',
'attio',
'calendly',
'fathom',
'webflow',
'typeform',
'grain',
@@ -1923,6 +2089,12 @@ export async function createExternalWebhookSubscription(
updatedProviderConfig = { ...updatedProviderConfig, webhookTag: usedTag }
}
externalSubscriptionCreated = true
} else if (provider === 'fathom') {
const result = await createFathomWebhookSubscription(request, webhookData, requestId)
if (result) {
updatedProviderConfig = { ...updatedProviderConfig, externalId: result.id }
externalSubscriptionCreated = true
}
} else if (provider === 'grain') {
const result = await createGrainWebhookSubscription(request, webhookData, requestId)
if (result) {
@@ -1968,6 +2140,8 @@ export async function cleanupExternalWebhook(
await deleteCalendlyWebhook(webhook, requestId)
} else if (webhook.provider === 'webflow') {
await deleteWebflowWebhook(webhook, workflow, requestId)
} else if (webhook.provider === 'fathom') {
await deleteFathomWebhook(webhook, requestId)
} else if (webhook.provider === 'grain') {
await deleteGrainWebhook(webhook, requestId)
} else if (webhook.provider === 'lemlist') {

View File

@@ -0,0 +1,74 @@
import type { FathomGetSummaryParams, FathomGetSummaryResponse } from '@/tools/fathom/types'
import type { ToolConfig } from '@/tools/types'
export const getSummaryTool: ToolConfig<FathomGetSummaryParams, FathomGetSummaryResponse> = {
id: 'fathom_get_summary',
name: 'Fathom Get Summary',
description: 'Get the call summary for a specific meeting recording.',
version: '1.0.0',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Fathom API Key',
},
recordingId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The recording ID of the meeting',
},
},
request: {
url: (params) =>
`https://api.fathom.ai/external/v1/recordings/${encodeURIComponent(params.recordingId.trim())}/summary`,
method: 'GET',
headers: (params) => ({
'X-Api-Key': params.apiKey,
'Content-Type': 'application/json',
}),
},
transformResponse: async (response: Response) => {
if (!response.ok) {
const errorData = await response.json().catch(() => ({}))
return {
success: false,
error:
(errorData as Record<string, string>).message ||
`Fathom API error: ${response.status} ${response.statusText}`,
output: {
template_name: null,
markdown_formatted: null,
},
}
}
const data = await response.json()
const summary = data.summary ?? data
return {
success: true,
output: {
template_name: summary.template_name ?? null,
markdown_formatted: summary.markdown_formatted ?? null,
},
}
},
outputs: {
template_name: {
type: 'string',
description: 'Name of the summary template used',
optional: true,
},
markdown_formatted: {
type: 'string',
description: 'Markdown-formatted summary text',
optional: true,
},
},
}

View File

@@ -0,0 +1,95 @@
import type { FathomGetTranscriptParams, FathomGetTranscriptResponse } from '@/tools/fathom/types'
import type { ToolConfig } from '@/tools/types'
export const getTranscriptTool: ToolConfig<FathomGetTranscriptParams, FathomGetTranscriptResponse> =
{
id: 'fathom_get_transcript',
name: 'Fathom Get Transcript',
description: 'Get the full transcript for a specific meeting recording.',
version: '1.0.0',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Fathom API Key',
},
recordingId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The recording ID of the meeting',
},
},
request: {
url: (params) =>
`https://api.fathom.ai/external/v1/recordings/${encodeURIComponent(params.recordingId.trim())}/transcript`,
method: 'GET',
headers: (params) => ({
'X-Api-Key': params.apiKey,
'Content-Type': 'application/json',
}),
},
transformResponse: async (response: Response) => {
if (!response.ok) {
const errorData = await response.json().catch(() => ({}))
return {
success: false,
error:
(errorData as Record<string, string>).message ||
`Fathom API error: ${response.status} ${response.statusText}`,
output: {
transcript: [],
},
}
}
const data = await response.json()
const transcript = (data.transcript ?? []).map(
(entry: { speaker?: Record<string, unknown>; text?: string; timestamp?: string }) => ({
speaker: {
display_name: entry.speaker?.display_name ?? '',
matched_calendar_invitee_email: entry.speaker?.matched_calendar_invitee_email ?? null,
},
text: entry.text ?? '',
timestamp: entry.timestamp ?? '',
})
)
return {
success: true,
output: {
transcript,
},
}
},
outputs: {
transcript: {
type: 'array',
description: 'Array of transcript entries with speaker, text, and timestamp',
items: {
type: 'object',
properties: {
speaker: {
type: 'object',
description: 'Speaker information',
properties: {
display_name: { type: 'string', description: 'Speaker display name' },
matched_calendar_invitee_email: {
type: 'string',
description: 'Matched calendar invitee email',
optional: true,
},
},
},
text: { type: 'string', description: 'Transcript text' },
timestamp: { type: 'string', description: 'Timestamp (HH:MM:SS)' },
},
},
},
},
}

View File

@@ -0,0 +1,13 @@
import { getSummaryTool } from '@/tools/fathom/get_summary'
import { getTranscriptTool } from '@/tools/fathom/get_transcript'
import { listMeetingsTool } from '@/tools/fathom/list_meetings'
import { listTeamMembersTool } from '@/tools/fathom/list_team_members'
import { listTeamsTool } from '@/tools/fathom/list_teams'
export const fathomGetSummaryTool = getSummaryTool
export const fathomGetTranscriptTool = getTranscriptTool
export const fathomListMeetingsTool = listMeetingsTool
export const fathomListTeamMembersTool = listTeamMembersTool
export const fathomListTeamsTool = listTeamsTool
export * from './types'

View File

@@ -0,0 +1,174 @@
import type { FathomListMeetingsParams, FathomListMeetingsResponse } from '@/tools/fathom/types'
import type { ToolConfig } from '@/tools/types'
export const listMeetingsTool: ToolConfig<FathomListMeetingsParams, FathomListMeetingsResponse> = {
id: 'fathom_list_meetings',
name: 'Fathom List Meetings',
description: 'List recent meetings recorded by the user or shared to their team.',
version: '1.0.0',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Fathom API Key',
},
includeSummary: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Include meeting summary (true/false)',
},
includeTranscript: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Include meeting transcript (true/false)',
},
includeActionItems: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Include action items (true/false)',
},
includeCrmMatches: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Include linked CRM matches (true/false)',
},
createdAfter: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Filter meetings created after this ISO 8601 timestamp',
},
createdBefore: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Filter meetings created before this ISO 8601 timestamp',
},
recordedBy: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Filter by recorder email address',
},
teams: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Filter by team name',
},
cursor: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Pagination cursor from a previous response',
},
},
request: {
url: (params) => {
const url = new URL('https://api.fathom.ai/external/v1/meetings')
if (params.includeSummary === 'true') url.searchParams.append('include_summary', 'true')
if (params.includeTranscript === 'true') url.searchParams.append('include_transcript', 'true')
if (params.includeActionItems === 'true')
url.searchParams.append('include_action_items', 'true')
if (params.includeCrmMatches === 'true')
url.searchParams.append('include_crm_matches', 'true')
if (params.createdAfter) url.searchParams.append('created_after', params.createdAfter)
if (params.createdBefore) url.searchParams.append('created_before', params.createdBefore)
if (params.recordedBy) url.searchParams.append('recorded_by[]', params.recordedBy)
if (params.teams) url.searchParams.append('teams[]', params.teams)
if (params.cursor) url.searchParams.append('cursor', params.cursor)
return url.toString()
},
method: 'GET',
headers: (params) => ({
'X-Api-Key': params.apiKey,
'Content-Type': 'application/json',
}),
},
transformResponse: async (response: Response) => {
if (!response.ok) {
const errorData = await response.json().catch(() => ({}))
return {
success: false,
error:
(errorData as Record<string, string>).message ||
`Fathom API error: ${response.status} ${response.statusText}`,
output: {
meetings: [],
next_cursor: null,
},
}
}
const data = await response.json()
const meetings = (data.items ?? []).map(
(meeting: Record<string, unknown> & { recorded_by?: Record<string, unknown> }) => ({
title: meeting.title ?? '',
meeting_title: meeting.meeting_title ?? null,
recording_id: meeting.recording_id ?? null,
url: meeting.url ?? '',
share_url: meeting.share_url ?? '',
created_at: meeting.created_at ?? '',
scheduled_start_time: meeting.scheduled_start_time ?? null,
scheduled_end_time: meeting.scheduled_end_time ?? null,
recording_start_time: meeting.recording_start_time ?? null,
recording_end_time: meeting.recording_end_time ?? null,
transcript_language: meeting.transcript_language ?? '',
calendar_invitees_domains_type: meeting.calendar_invitees_domains_type ?? null,
recorded_by: meeting.recorded_by
? {
name: meeting.recorded_by.name ?? '',
email: meeting.recorded_by.email ?? '',
email_domain: meeting.recorded_by.email_domain ?? '',
team: meeting.recorded_by.team ?? null,
}
: null,
calendar_invitees: (meeting.calendar_invitees as Array<Record<string, unknown>>) ?? [],
default_summary: meeting.default_summary ?? null,
transcript: meeting.transcript ?? null,
action_items: meeting.action_items ?? null,
crm_matches: meeting.crm_matches ?? null,
})
)
return {
success: true,
output: {
meetings,
next_cursor: data.next_cursor ?? null,
},
}
},
outputs: {
meetings: {
type: 'array',
description: 'List of meetings',
items: {
type: 'object',
properties: {
title: { type: 'string', description: 'Meeting title' },
recording_id: { type: 'number', description: 'Unique recording ID' },
url: { type: 'string', description: 'URL to view the meeting' },
share_url: { type: 'string', description: 'Shareable URL' },
created_at: { type: 'string', description: 'Creation timestamp' },
transcript_language: { type: 'string', description: 'Transcript language' },
},
},
},
next_cursor: {
type: 'string',
description: 'Pagination cursor for next page',
optional: true,
},
},
}

View File

@@ -0,0 +1,103 @@
import type {
FathomListTeamMembersParams,
FathomListTeamMembersResponse,
} from '@/tools/fathom/types'
import type { ToolConfig } from '@/tools/types'
export const listTeamMembersTool: ToolConfig<
FathomListTeamMembersParams,
FathomListTeamMembersResponse
> = {
id: 'fathom_list_team_members',
name: 'Fathom List Team Members',
description: 'List team members in your Fathom organization.',
version: '1.0.0',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Fathom API Key',
},
teams: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Team name to filter by',
},
cursor: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Pagination cursor from a previous response',
},
},
request: {
url: (params) => {
const url = new URL('https://api.fathom.ai/external/v1/team_members')
if (params.teams) url.searchParams.append('team', params.teams)
if (params.cursor) url.searchParams.append('cursor', params.cursor)
return url.toString()
},
method: 'GET',
headers: (params) => ({
'X-Api-Key': params.apiKey,
'Content-Type': 'application/json',
}),
},
transformResponse: async (response: Response) => {
if (!response.ok) {
const errorData = await response.json().catch(() => ({}))
return {
success: false,
error:
(errorData as Record<string, string>).message ||
`Fathom API error: ${response.status} ${response.statusText}`,
output: {
members: [],
next_cursor: null,
},
}
}
const data = await response.json()
const members = (data.items ?? []).map(
(member: { name?: string; email?: string; created_at?: string }) => ({
name: member.name ?? '',
email: member.email ?? '',
created_at: member.created_at ?? '',
})
)
return {
success: true,
output: {
members,
next_cursor: data.next_cursor ?? null,
},
}
},
outputs: {
members: {
type: 'array',
description: 'List of team members',
items: {
type: 'object',
properties: {
name: { type: 'string', description: 'Team member name' },
email: { type: 'string', description: 'Team member email' },
created_at: { type: 'string', description: 'Date the member was added' },
},
},
},
next_cursor: {
type: 'string',
description: 'Pagination cursor for next page',
optional: true,
},
},
}

View File

@@ -0,0 +1,86 @@
import type { FathomListTeamsParams, FathomListTeamsResponse } from '@/tools/fathom/types'
import type { ToolConfig } from '@/tools/types'
export const listTeamsTool: ToolConfig<FathomListTeamsParams, FathomListTeamsResponse> = {
id: 'fathom_list_teams',
name: 'Fathom List Teams',
description: 'List teams in your Fathom organization.',
version: '1.0.0',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Fathom API Key',
},
cursor: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Pagination cursor from a previous response',
},
},
request: {
url: (params) => {
const url = new URL('https://api.fathom.ai/external/v1/teams')
if (params.cursor) url.searchParams.append('cursor', params.cursor)
return url.toString()
},
method: 'GET',
headers: (params) => ({
'X-Api-Key': params.apiKey,
'Content-Type': 'application/json',
}),
},
transformResponse: async (response: Response) => {
if (!response.ok) {
const errorData = await response.json().catch(() => ({}))
return {
success: false,
error:
(errorData as Record<string, string>).message ||
`Fathom API error: ${response.status} ${response.statusText}`,
output: {
teams: [],
next_cursor: null,
},
}
}
const data = await response.json()
const teams = (data.items ?? []).map((team: { name?: string; created_at?: string }) => ({
name: team.name ?? '',
created_at: team.created_at ?? '',
}))
return {
success: true,
output: {
teams,
next_cursor: data.next_cursor ?? null,
},
}
},
outputs: {
teams: {
type: 'array',
description: 'List of teams',
items: {
type: 'object',
properties: {
name: { type: 'string', description: 'Team name' },
created_at: { type: 'string', description: 'Date the team was created' },
},
},
},
next_cursor: {
type: 'string',
description: 'Pagination cursor for next page',
optional: true,
},
},
}

View File

@@ -0,0 +1,127 @@
import type { ToolResponse } from '@/tools/types'
export interface FathomBaseParams {
apiKey: string
}
export interface FathomListMeetingsParams extends FathomBaseParams {
includeSummary?: string
includeTranscript?: string
includeActionItems?: string
includeCrmMatches?: string
createdAfter?: string
createdBefore?: string
recordedBy?: string
teams?: string
cursor?: string
}
export interface FathomListMeetingsResponse extends ToolResponse {
output: {
meetings: Array<{
title: string
meeting_title: string | null
recording_id: number | null
url: string
share_url: string
created_at: string
scheduled_start_time: string | null
scheduled_end_time: string | null
recording_start_time: string | null
recording_end_time: string | null
transcript_language: string
calendar_invitees_domains_type: string | null
recorded_by: { name: string; email: string; email_domain: string; team: string | null } | null
calendar_invitees: Array<{
name: string | null
email: string
email_domain: string | null
is_external: boolean
matched_speaker_display_name: string | null
}>
default_summary: { template_name: string | null; markdown_formatted: string | null } | null
transcript: Array<{
speaker: { display_name: string; matched_calendar_invitee_email: string | null }
text: string
timestamp: string
}> | null
action_items: Array<{
description: string
user_generated: boolean
completed: boolean
recording_timestamp: string
recording_playback_url: string
assignee: { name: string | null; email: string | null; team: string | null }
}> | null
crm_matches: {
contacts: Array<{ name: string; email: string; record_url: string }>
companies: Array<{ name: string; record_url: string }>
deals: Array<{ name: string; amount: number; record_url: string }>
error: string | null
} | null
}>
next_cursor: string | null
}
}
export interface FathomGetSummaryParams extends FathomBaseParams {
recordingId: string
}
export interface FathomGetSummaryResponse extends ToolResponse {
output: {
template_name: string | null
markdown_formatted: string | null
}
}
export interface FathomGetTranscriptParams extends FathomBaseParams {
recordingId: string
}
export interface FathomGetTranscriptResponse extends ToolResponse {
output: {
transcript: Array<{
speaker: { display_name: string; matched_calendar_invitee_email: string | null }
text: string
timestamp: string
}>
}
}
export interface FathomListTeamMembersParams extends FathomBaseParams {
teams?: string
cursor?: string
}
export interface FathomListTeamMembersResponse extends ToolResponse {
output: {
members: Array<{
name: string
email: string
created_at: string
}>
next_cursor: string | null
}
}
export interface FathomListTeamsParams extends FathomBaseParams {
cursor?: string
}
export interface FathomListTeamsResponse extends ToolResponse {
output: {
teams: Array<{
name: string
created_at: string
}>
next_cursor: string | null
}
}
export type FathomResponse =
| FathomListMeetingsResponse
| FathomGetSummaryResponse
| FathomGetTranscriptResponse
| FathomListTeamMembersResponse
| FathomListTeamsResponse

View File

@@ -446,6 +446,13 @@ import {
exaResearchTool,
exaSearchTool,
} from '@/tools/exa'
import {
fathomGetSummaryTool,
fathomGetTranscriptTool,
fathomListMeetingsTool,
fathomListTeamMembersTool,
fathomListTeamsTool,
} from '@/tools/fathom'
import { fileParserV2Tool, fileParserV3Tool, fileParseTool } from '@/tools/file'
import {
firecrawlAgentTool,
@@ -3666,6 +3673,11 @@ export const tools: Record<string, ToolConfig> = {
knowledge_create_document: knowledgeCreateDocumentTool,
search_tool: searchTool,
elevenlabs_tts: elevenLabsTtsTool,
fathom_list_meetings: fathomListMeetingsTool,
fathom_get_summary: fathomGetSummaryTool,
fathom_get_transcript: fathomGetTranscriptTool,
fathom_list_team_members: fathomListTeamMembersTool,
fathom_list_teams: fathomListTeamsTool,
stt_whisper: whisperSttTool,
stt_whisper_v2: whisperSttV2Tool,
stt_deepgram: deepgramSttTool,

View File

@@ -0,0 +1,2 @@
export { fathomNewMeetingTrigger } from './new_meeting'
export { fathomWebhookTrigger } from './webhook'

View File

@@ -0,0 +1,128 @@
import { FathomIcon } from '@/components/icons'
import type { TriggerConfig } from '@/triggers/types'
import { buildMeetingOutputs, fathomSetupInstructions } from './utils'
export const fathomNewMeetingTrigger: TriggerConfig = {
id: 'fathom_new_meeting',
name: 'Fathom New Meeting Content',
provider: 'fathom',
description: 'Trigger workflow when new meeting content is ready in Fathom',
version: '1.0.0',
icon: FathomIcon,
subBlocks: [
{
id: 'apiKey',
title: 'API Key',
type: 'short-input',
placeholder: 'Enter your Fathom API key',
description: 'Required to create the webhook in Fathom.',
password: true,
required: true,
mode: 'trigger',
condition: {
field: 'selectedTriggerId',
value: 'fathom_new_meeting',
},
},
{
id: 'triggeredFor',
title: 'Trigger For',
type: 'dropdown',
options: [
{ label: 'My Recordings', id: 'my_recordings' },
{ label: 'Shared External Recordings', id: 'shared_external_recordings' },
{ label: 'My Shared With Team Recordings', id: 'my_shared_with_team_recordings' },
{ label: 'Shared Team Recordings', id: 'shared_team_recordings' },
],
value: () => 'my_recordings',
description: 'Which recording types should trigger this webhook.',
mode: 'trigger',
condition: {
field: 'selectedTriggerId',
value: 'fathom_new_meeting',
},
},
{
id: 'includeSummary',
title: 'Include Summary',
type: 'switch',
description: 'Include the meeting summary in the webhook payload.',
defaultValue: true,
mode: 'trigger',
condition: {
field: 'selectedTriggerId',
value: 'fathom_new_meeting',
},
},
{
id: 'includeTranscript',
title: 'Include Transcript',
type: 'switch',
description: 'Include the full transcript in the webhook payload.',
defaultValue: false,
mode: 'trigger',
condition: {
field: 'selectedTriggerId',
value: 'fathom_new_meeting',
},
},
{
id: 'includeActionItems',
title: 'Include Action Items',
type: 'switch',
description: 'Include action items extracted from the meeting.',
defaultValue: false,
mode: 'trigger',
condition: {
field: 'selectedTriggerId',
value: 'fathom_new_meeting',
},
},
{
id: 'includeCrmMatches',
title: 'Include CRM Matches',
type: 'switch',
description: 'Include matched CRM contacts, companies, and deals from your linked CRM.',
defaultValue: false,
mode: 'trigger',
condition: {
field: 'selectedTriggerId',
value: 'fathom_new_meeting',
},
},
{
id: 'triggerSave',
title: '',
type: 'trigger-save',
hideFromPreview: true,
mode: 'trigger',
triggerId: 'fathom_new_meeting',
condition: {
field: 'selectedTriggerId',
value: 'fathom_new_meeting',
},
},
{
id: 'triggerInstructions',
title: 'Setup Instructions',
hideFromPreview: true,
type: 'text',
defaultValue: fathomSetupInstructions('New Meeting Content'),
mode: 'trigger',
condition: {
field: 'selectedTriggerId',
value: 'fathom_new_meeting',
},
},
],
outputs: buildMeetingOutputs(),
webhook: {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
},
}

View File

@@ -0,0 +1,123 @@
import type { TriggerOutput } from '@/triggers/types'
/**
* Shared trigger dropdown options for all Fathom triggers
*/
export const fathomTriggerOptions = [
{ label: 'New Meeting Content', id: 'fathom_new_meeting' },
{ label: 'General Webhook (All Events)', id: 'fathom_webhook' },
]
/**
* Generate setup instructions for a specific Fathom event type
*/
export function fathomSetupInstructions(eventType: string): string {
const instructions = [
'Enter your Fathom API Key above.',
'You can find or create your API key in Fathom at <strong>Settings > Integrations > API</strong>. See the <a href="https://developers.fathom.ai/" target="_blank" rel="noopener noreferrer">Fathom API documentation</a> for details.',
`Click <strong>"Save Configuration"</strong> to automatically create the webhook in Fathom for <strong>${eventType}</strong> events.`,
'The webhook will be automatically deleted when you remove this trigger.',
]
return instructions
.map(
(instruction, index) =>
`<div class="mb-3"><strong>${index + 1}.</strong> ${instruction}</div>`
)
.join('')
}
/**
* Build output schema for meeting content events.
* Fathom webhook payload delivers meeting data including summary, transcript, and action items
* based on the include flags set during webhook creation.
*/
export function buildMeetingOutputs(): Record<string, TriggerOutput> {
return {
title: {
type: 'string',
description: 'Meeting title',
},
meeting_title: {
type: 'string',
description: 'Calendar event title',
},
recording_id: {
type: 'number',
description: 'Unique recording ID',
},
url: {
type: 'string',
description: 'URL to view the meeting in Fathom',
},
share_url: {
type: 'string',
description: 'Shareable URL for the meeting',
},
created_at: {
type: 'string',
description: 'ISO 8601 creation timestamp',
},
scheduled_start_time: {
type: 'string',
description: 'Scheduled start time',
},
scheduled_end_time: {
type: 'string',
description: 'Scheduled end time',
},
recording_start_time: {
type: 'string',
description: 'Recording start time',
},
recording_end_time: {
type: 'string',
description: 'Recording end time',
},
transcript_language: {
type: 'string',
description: 'Language of the transcript',
},
calendar_invitees_domains_type: {
type: 'string',
description: 'Domain type: only_internal or one_or_more_external',
},
recorded_by: {
type: 'object',
description: 'Recorder details',
name: { type: 'string', description: 'Name of the recorder' },
email: { type: 'string', description: 'Email of the recorder' },
},
calendar_invitees: {
type: 'array',
description: 'Array of calendar invitees with name and email',
},
default_summary: {
type: 'object',
description: 'Meeting summary',
template_name: { type: 'string', description: 'Summary template name' },
markdown_formatted: { type: 'string', description: 'Markdown-formatted summary' },
},
transcript: {
type: 'array',
description: 'Array of transcript entries with speaker, text, and timestamp',
},
action_items: {
type: 'array',
description: 'Array of action items extracted from the meeting',
},
crm_matches: {
type: 'json',
description: 'Matched CRM contacts, companies, and deals from linked CRM',
},
} as Record<string, TriggerOutput>
}
/**
* Build output schema for generic webhook events.
* Fathom only has one webhook event type (new meeting content ready) and the payload
* is the Meeting object directly (no wrapping), so outputs match buildMeetingOutputs.
*/
export function buildGenericOutputs(): Record<string, TriggerOutput> {
return buildMeetingOutputs()
}

View File

@@ -0,0 +1,128 @@
import { FathomIcon } from '@/components/icons'
import type { TriggerConfig } from '@/triggers/types'
import { buildGenericOutputs, fathomSetupInstructions } from './utils'
export const fathomWebhookTrigger: TriggerConfig = {
id: 'fathom_webhook',
name: 'Fathom Webhook',
provider: 'fathom',
description: 'Generic webhook trigger for all Fathom events',
version: '1.0.0',
icon: FathomIcon,
subBlocks: [
{
id: 'apiKey',
title: 'API Key',
type: 'short-input',
placeholder: 'Enter your Fathom API key',
description: 'Required to create the webhook in Fathom.',
password: true,
required: true,
mode: 'trigger',
condition: {
field: 'selectedTriggerId',
value: 'fathom_webhook',
},
},
{
id: 'triggeredFor',
title: 'Trigger For',
type: 'dropdown',
options: [
{ label: 'My Recordings', id: 'my_recordings' },
{ label: 'Shared External Recordings', id: 'shared_external_recordings' },
{ label: 'My Shared With Team Recordings', id: 'my_shared_with_team_recordings' },
{ label: 'Shared Team Recordings', id: 'shared_team_recordings' },
],
value: () => 'my_recordings',
description: 'Which recording types should trigger this webhook.',
mode: 'trigger',
condition: {
field: 'selectedTriggerId',
value: 'fathom_webhook',
},
},
{
id: 'includeSummary',
title: 'Include Summary',
type: 'switch',
description: 'Include the meeting summary in the webhook payload.',
defaultValue: true,
mode: 'trigger',
condition: {
field: 'selectedTriggerId',
value: 'fathom_webhook',
},
},
{
id: 'includeTranscript',
title: 'Include Transcript',
type: 'switch',
description: 'Include the full transcript in the webhook payload.',
defaultValue: false,
mode: 'trigger',
condition: {
field: 'selectedTriggerId',
value: 'fathom_webhook',
},
},
{
id: 'includeActionItems',
title: 'Include Action Items',
type: 'switch',
description: 'Include action items extracted from the meeting.',
defaultValue: false,
mode: 'trigger',
condition: {
field: 'selectedTriggerId',
value: 'fathom_webhook',
},
},
{
id: 'includeCrmMatches',
title: 'Include CRM Matches',
type: 'switch',
description: 'Include matched CRM contacts, companies, and deals from your linked CRM.',
defaultValue: false,
mode: 'trigger',
condition: {
field: 'selectedTriggerId',
value: 'fathom_webhook',
},
},
{
id: 'triggerSave',
title: '',
type: 'trigger-save',
hideFromPreview: true,
mode: 'trigger',
triggerId: 'fathom_webhook',
condition: {
field: 'selectedTriggerId',
value: 'fathom_webhook',
},
},
{
id: 'triggerInstructions',
title: 'Setup Instructions',
hideFromPreview: true,
type: 'text',
defaultValue: fathomSetupInstructions('All Events'),
mode: 'trigger',
condition: {
field: 'selectedTriggerId',
value: 'fathom_webhook',
},
},
],
outputs: buildGenericOutputs(),
webhook: {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
},
}

View File

@@ -59,6 +59,7 @@ import {
confluenceSpaceUpdatedTrigger,
confluenceWebhookTrigger,
} from '@/triggers/confluence'
import { fathomNewMeetingTrigger, fathomWebhookTrigger } from '@/triggers/fathom'
import { firefliesTranscriptionCompleteTrigger } from '@/triggers/fireflies'
import { genericWebhookTrigger } from '@/triggers/generic'
import {
@@ -226,6 +227,8 @@ export const TRIGGER_REGISTRY: TriggerRegistry = {
github_release_published: githubReleasePublishedTrigger,
github_workflow_run: githubWorkflowRunTrigger,
fireflies_transcription_complete: firefliesTranscriptionCompleteTrigger,
fathom_new_meeting: fathomNewMeetingTrigger,
fathom_webhook: fathomWebhookTrigger,
gmail_poller: gmailPollingTrigger,
grain_webhook: grainWebhookTrigger,
grain_recording_created: grainRecordingCreatedTrigger,