From c9a1e21d2d9db988a8c7acca6f137c4cd3b95518 Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Mon, 6 Apr 2026 11:20:10 -0700 Subject: [PATCH 1/2] feat(triggers): add Intercom webhook triggers --- .../integrations/data/integrations.json | 35 +++- apps/sim/blocks/blocks/intercom.ts | 21 +++ apps/sim/lib/webhooks/providers/intercom.ts | 120 +++++++++++++ apps/sim/lib/webhooks/providers/registry.ts | 2 + apps/sim/triggers/intercom/contact_created.ts | 41 +++++ .../triggers/intercom/conversation_closed.ts | 39 +++++ .../triggers/intercom/conversation_created.ts | 43 +++++ .../triggers/intercom/conversation_reply.ts | 41 +++++ apps/sim/triggers/intercom/index.ts | 6 + apps/sim/triggers/intercom/user_created.ts | 41 +++++ apps/sim/triggers/intercom/utils.ts | 158 ++++++++++++++++++ apps/sim/triggers/intercom/webhook.ts | 41 +++++ apps/sim/triggers/registry.ts | 14 ++ 13 files changed, 600 insertions(+), 2 deletions(-) create mode 100644 apps/sim/lib/webhooks/providers/intercom.ts create mode 100644 apps/sim/triggers/intercom/contact_created.ts create mode 100644 apps/sim/triggers/intercom/conversation_closed.ts create mode 100644 apps/sim/triggers/intercom/conversation_created.ts create mode 100644 apps/sim/triggers/intercom/conversation_reply.ts create mode 100644 apps/sim/triggers/intercom/index.ts create mode 100644 apps/sim/triggers/intercom/user_created.ts create mode 100644 apps/sim/triggers/intercom/utils.ts create mode 100644 apps/sim/triggers/intercom/webhook.ts diff --git a/apps/sim/app/(landing)/integrations/data/integrations.json b/apps/sim/app/(landing)/integrations/data/integrations.json index 9db82b6d349..b920d1b2ffc 100644 --- a/apps/sim/app/(landing)/integrations/data/integrations.json +++ b/apps/sim/app/(landing)/integrations/data/integrations.json @@ -6077,8 +6077,39 @@ } ], "operationCount": 31, - "triggers": [], - "triggerCount": 0, + "triggers": [ + { + "id": "intercom_conversation_created", + "name": "Intercom Conversation Created", + "description": "Trigger workflow when a new conversation is created in Intercom" + }, + { + "id": "intercom_conversation_reply", + "name": "Intercom Conversation Reply", + "description": "Trigger workflow when someone replies to an Intercom conversation" + }, + { + "id": "intercom_conversation_closed", + "name": "Intercom Conversation Closed", + "description": "Trigger workflow when a conversation is closed in Intercom" + }, + { + "id": "intercom_contact_created", + "name": "Intercom Contact Created", + "description": "Trigger workflow when a new lead is created in Intercom" + }, + { + "id": "intercom_user_created", + "name": "Intercom User Created", + "description": "Trigger workflow when a new user is created in Intercom" + }, + { + "id": "intercom_webhook", + "name": "Intercom Webhook (All Events)", + "description": "Trigger workflow on any Intercom webhook event" + } + ], + "triggerCount": 6, "authType": "api-key", "category": "tools", "integrationType": "customer-support", diff --git a/apps/sim/blocks/blocks/intercom.ts b/apps/sim/blocks/blocks/intercom.ts index 21b8124324a..a044cb57ca0 100644 --- a/apps/sim/blocks/blocks/intercom.ts +++ b/apps/sim/blocks/blocks/intercom.ts @@ -2,6 +2,7 @@ import { IntercomIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' import { AuthMode, IntegrationType } from '@/blocks/types' import { createVersionedToolSelector } from '@/blocks/utils' +import { getTrigger } from '@/triggers' export const IntercomBlock: BlockConfig = { type: 'intercom', @@ -1409,6 +1410,26 @@ export const IntercomV2Block: BlockConfig = { integrationType: IntegrationType.CustomerSupport, tags: ['customer-support', 'messaging'], hideFromToolbar: false, + subBlocks: [ + ...IntercomBlock.subBlocks, + ...getTrigger('intercom_conversation_created').subBlocks, + ...getTrigger('intercom_conversation_reply').subBlocks, + ...getTrigger('intercom_conversation_closed').subBlocks, + ...getTrigger('intercom_contact_created').subBlocks, + ...getTrigger('intercom_user_created').subBlocks, + ...getTrigger('intercom_webhook').subBlocks, + ], + triggers: { + enabled: true, + available: [ + 'intercom_conversation_created', + 'intercom_conversation_reply', + 'intercom_conversation_closed', + 'intercom_contact_created', + 'intercom_user_created', + 'intercom_webhook', + ], + }, tools: { ...IntercomBlock.tools, access: [ diff --git a/apps/sim/lib/webhooks/providers/intercom.ts b/apps/sim/lib/webhooks/providers/intercom.ts new file mode 100644 index 00000000000..5957a93b1fe --- /dev/null +++ b/apps/sim/lib/webhooks/providers/intercom.ts @@ -0,0 +1,120 @@ +import crypto from 'crypto' +import { createLogger } from '@sim/logger' +import { NextResponse } from 'next/server' +import { safeCompare } from '@/lib/core/security/encryption' +import type { + AuthContext, + EventMatchContext, + FormatInputContext, + FormatInputResult, + WebhookProviderHandler, +} from '@/lib/webhooks/providers/types' + +const logger = createLogger('WebhookProvider:Intercom') + +/** + * Validate Intercom webhook signature using HMAC-SHA1. + * Intercom signs payloads with the app's Client Secret and sends the + * signature in the X-Hub-Signature header as "sha1=". + */ +function validateIntercomSignature(secret: string, signature: string, body: string): boolean { + try { + if (!secret || !signature || !body) { + logger.warn('Intercom signature validation missing required fields', { + hasSecret: !!secret, + hasSignature: !!signature, + hasBody: !!body, + }) + return false + } + + if (!signature.startsWith('sha1=')) { + logger.warn('Intercom signature has invalid format', { + signature: `${signature.substring(0, 10)}...`, + }) + return false + } + + const providedSignature = signature.substring(5) + const computedHash = crypto.createHmac('sha1', secret).update(body, 'utf8').digest('hex') + + return safeCompare(computedHash, providedSignature) + } catch (error) { + logger.error('Error validating Intercom signature:', error) + return false + } +} + +export const intercomHandler: WebhookProviderHandler = { + verifyAuth({ request, rawBody, requestId, providerConfig }: AuthContext) { + const secret = providerConfig.webhookSecret as string | undefined + if (!secret) { + return null + } + + const signature = request.headers.get('X-Hub-Signature') + if (!signature) { + logger.warn(`[${requestId}] Intercom webhook missing X-Hub-Signature header`) + return new NextResponse('Unauthorized - Missing Intercom signature', { status: 401 }) + } + + if (!validateIntercomSignature(secret, signature, rawBody)) { + logger.warn(`[${requestId}] Intercom signature verification failed`, { + signatureLength: signature.length, + secretLength: secret.length, + }) + return new NextResponse('Unauthorized - Invalid Intercom signature', { status: 401 }) + } + + return null + }, + + handleReachabilityTest(body: unknown, requestId: string) { + const obj = body as Record | null + if (obj?.topic === 'ping') { + logger.info( + `[${requestId}] Intercom ping event detected - returning 200 without triggering workflow` + ) + return NextResponse.json({ + status: 'ok', + message: 'Webhook endpoint verified', + }) + } + return null + }, + + async formatInput({ body }: FormatInputContext): Promise { + return { input: body } + }, + + async matchEvent({ webhook, body, requestId, providerConfig }: EventMatchContext) { + const triggerId = providerConfig.triggerId as string | undefined + const obj = body as Record + const topic = obj?.topic as string | undefined + + if (triggerId && triggerId !== 'intercom_webhook') { + const { isIntercomEventMatch } = await import('@/triggers/intercom/utils') + if (!isIntercomEventMatch(triggerId, topic || '')) { + logger.debug( + `[${requestId}] Intercom event mismatch for trigger ${triggerId}. Topic: ${topic}. Skipping execution.`, + { + webhookId: webhook.id, + triggerId, + receivedTopic: topic, + } + ) + return false + } + } + + return true + }, + + extractIdempotencyId(body: unknown) { + const obj = body as Record + if (obj?.id && obj?.type === 'notification_event') { + return String(obj.id) + } + return null + }, +} diff --git a/apps/sim/lib/webhooks/providers/registry.ts b/apps/sim/lib/webhooks/providers/registry.ts index 00ae58a21b1..5d4828b26fb 100644 --- a/apps/sim/lib/webhooks/providers/registry.ts +++ b/apps/sim/lib/webhooks/providers/registry.ts @@ -16,6 +16,7 @@ import { googleFormsHandler } from '@/lib/webhooks/providers/google-forms' import { grainHandler } from '@/lib/webhooks/providers/grain' import { hubspotHandler } from '@/lib/webhooks/providers/hubspot' import { imapHandler } from '@/lib/webhooks/providers/imap' +import { intercomHandler } from '@/lib/webhooks/providers/intercom' import { jiraHandler } from '@/lib/webhooks/providers/jira' import { lemlistHandler } from '@/lib/webhooks/providers/lemlist' import { linearHandler } from '@/lib/webhooks/providers/linear' @@ -52,6 +53,7 @@ const PROVIDER_HANDLERS: Record = { grain: grainHandler, hubspot: hubspotHandler, imap: imapHandler, + intercom: intercomHandler, jira: jiraHandler, lemlist: lemlistHandler, linear: linearHandler, diff --git a/apps/sim/triggers/intercom/contact_created.ts b/apps/sim/triggers/intercom/contact_created.ts new file mode 100644 index 00000000000..f9602072c52 --- /dev/null +++ b/apps/sim/triggers/intercom/contact_created.ts @@ -0,0 +1,41 @@ +import { IntercomIcon } from '@/components/icons' +import { buildTriggerSubBlocks } from '@/triggers' +import { + buildIntercomContactOutputs, + buildIntercomExtraFields, + intercomSetupInstructions, + intercomTriggerOptions, +} from '@/triggers/intercom/utils' +import type { TriggerConfig } from '@/triggers/types' + +/** + * Intercom Contact Created Trigger + * + * Fires when a new lead is created in Intercom. + * Note: In Intercom, contact.created fires for leads only. + * For identified users, use the User Created trigger (user.created topic). + */ +export const intercomContactCreatedTrigger: TriggerConfig = { + id: 'intercom_contact_created', + name: 'Intercom Contact Created', + provider: 'intercom', + description: 'Trigger workflow when a new lead is created in Intercom', + version: '1.0.0', + icon: IntercomIcon, + + subBlocks: buildTriggerSubBlocks({ + triggerId: 'intercom_contact_created', + triggerOptions: intercomTriggerOptions, + setupInstructions: intercomSetupInstructions('contact.created'), + extraFields: buildIntercomExtraFields('intercom_contact_created'), + }), + + outputs: buildIntercomContactOutputs(), + + webhook: { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + }, +} diff --git a/apps/sim/triggers/intercom/conversation_closed.ts b/apps/sim/triggers/intercom/conversation_closed.ts new file mode 100644 index 00000000000..f8b8e23d5c7 --- /dev/null +++ b/apps/sim/triggers/intercom/conversation_closed.ts @@ -0,0 +1,39 @@ +import { IntercomIcon } from '@/components/icons' +import { buildTriggerSubBlocks } from '@/triggers' +import { + buildIntercomConversationOutputs, + buildIntercomExtraFields, + intercomSetupInstructions, + intercomTriggerOptions, +} from '@/triggers/intercom/utils' +import type { TriggerConfig } from '@/triggers/types' + +/** + * Intercom Conversation Closed Trigger + * + * Fires when an admin closes a conversation. + */ +export const intercomConversationClosedTrigger: TriggerConfig = { + id: 'intercom_conversation_closed', + name: 'Intercom Conversation Closed', + provider: 'intercom', + description: 'Trigger workflow when a conversation is closed in Intercom', + version: '1.0.0', + icon: IntercomIcon, + + subBlocks: buildTriggerSubBlocks({ + triggerId: 'intercom_conversation_closed', + triggerOptions: intercomTriggerOptions, + setupInstructions: intercomSetupInstructions('conversation.admin.closed'), + extraFields: buildIntercomExtraFields('intercom_conversation_closed'), + }), + + outputs: buildIntercomConversationOutputs(), + + webhook: { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + }, +} diff --git a/apps/sim/triggers/intercom/conversation_created.ts b/apps/sim/triggers/intercom/conversation_created.ts new file mode 100644 index 00000000000..0d18273f760 --- /dev/null +++ b/apps/sim/triggers/intercom/conversation_created.ts @@ -0,0 +1,43 @@ +import { IntercomIcon } from '@/components/icons' +import { buildTriggerSubBlocks } from '@/triggers' +import { + buildIntercomConversationOutputs, + buildIntercomExtraFields, + intercomSetupInstructions, + intercomTriggerOptions, +} from '@/triggers/intercom/utils' +import type { TriggerConfig } from '@/triggers/types' + +/** + * Intercom Conversation Created Trigger + * + * This is the PRIMARY trigger - it includes the dropdown for selecting trigger type. + * Fires when a user/lead starts a new conversation or an admin initiates a 1:1 conversation. + */ +export const intercomConversationCreatedTrigger: TriggerConfig = { + id: 'intercom_conversation_created', + name: 'Intercom Conversation Created', + provider: 'intercom', + description: 'Trigger workflow when a new conversation is created in Intercom', + version: '1.0.0', + icon: IntercomIcon, + + subBlocks: buildTriggerSubBlocks({ + triggerId: 'intercom_conversation_created', + triggerOptions: intercomTriggerOptions, + includeDropdown: true, + setupInstructions: intercomSetupInstructions( + 'conversation.user.created and/or conversation.admin.single.created' + ), + extraFields: buildIntercomExtraFields('intercom_conversation_created'), + }), + + outputs: buildIntercomConversationOutputs(), + + webhook: { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + }, +} diff --git a/apps/sim/triggers/intercom/conversation_reply.ts b/apps/sim/triggers/intercom/conversation_reply.ts new file mode 100644 index 00000000000..df621517ee6 --- /dev/null +++ b/apps/sim/triggers/intercom/conversation_reply.ts @@ -0,0 +1,41 @@ +import { IntercomIcon } from '@/components/icons' +import { buildTriggerSubBlocks } from '@/triggers' +import { + buildIntercomConversationOutputs, + buildIntercomExtraFields, + intercomSetupInstructions, + intercomTriggerOptions, +} from '@/triggers/intercom/utils' +import type { TriggerConfig } from '@/triggers/types' + +/** + * Intercom Conversation Reply Trigger + * + * Fires when a user, lead, or admin replies to a conversation. + */ +export const intercomConversationReplyTrigger: TriggerConfig = { + id: 'intercom_conversation_reply', + name: 'Intercom Conversation Reply', + provider: 'intercom', + description: 'Trigger workflow when someone replies to an Intercom conversation', + version: '1.0.0', + icon: IntercomIcon, + + subBlocks: buildTriggerSubBlocks({ + triggerId: 'intercom_conversation_reply', + triggerOptions: intercomTriggerOptions, + setupInstructions: intercomSetupInstructions( + 'conversation.user.replied and/or conversation.admin.replied' + ), + extraFields: buildIntercomExtraFields('intercom_conversation_reply'), + }), + + outputs: buildIntercomConversationOutputs(), + + webhook: { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + }, +} diff --git a/apps/sim/triggers/intercom/index.ts b/apps/sim/triggers/intercom/index.ts new file mode 100644 index 00000000000..b465a9d42f5 --- /dev/null +++ b/apps/sim/triggers/intercom/index.ts @@ -0,0 +1,6 @@ +export { intercomContactCreatedTrigger } from './contact_created' +export { intercomConversationClosedTrigger } from './conversation_closed' +export { intercomConversationCreatedTrigger } from './conversation_created' +export { intercomConversationReplyTrigger } from './conversation_reply' +export { intercomUserCreatedTrigger } from './user_created' +export { intercomWebhookTrigger } from './webhook' diff --git a/apps/sim/triggers/intercom/user_created.ts b/apps/sim/triggers/intercom/user_created.ts new file mode 100644 index 00000000000..0c62f53adaf --- /dev/null +++ b/apps/sim/triggers/intercom/user_created.ts @@ -0,0 +1,41 @@ +import { IntercomIcon } from '@/components/icons' +import { buildTriggerSubBlocks } from '@/triggers' +import { + buildIntercomContactOutputs, + buildIntercomExtraFields, + intercomSetupInstructions, + intercomTriggerOptions, +} from '@/triggers/intercom/utils' +import type { TriggerConfig } from '@/triggers/types' + +/** + * Intercom User Created Trigger + * + * Fires when a new identified user is created in Intercom. + * Note: In Intercom, user.created fires for identified users only. + * For anonymous leads, use the Contact Created trigger (contact.created topic). + */ +export const intercomUserCreatedTrigger: TriggerConfig = { + id: 'intercom_user_created', + name: 'Intercom User Created', + provider: 'intercom', + description: 'Trigger workflow when a new user is created in Intercom', + version: '1.0.0', + icon: IntercomIcon, + + subBlocks: buildTriggerSubBlocks({ + triggerId: 'intercom_user_created', + triggerOptions: intercomTriggerOptions, + setupInstructions: intercomSetupInstructions('user.created'), + extraFields: buildIntercomExtraFields('intercom_user_created'), + }), + + outputs: buildIntercomContactOutputs(), + + webhook: { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + }, +} diff --git a/apps/sim/triggers/intercom/utils.ts b/apps/sim/triggers/intercom/utils.ts new file mode 100644 index 00000000000..e11f9e9a9ad --- /dev/null +++ b/apps/sim/triggers/intercom/utils.ts @@ -0,0 +1,158 @@ +import type { SubBlockConfig } from '@/blocks/types' +import type { TriggerOutput } from '@/triggers/types' + +/** + * Dropdown options for the Intercom trigger type selector. + */ +export const intercomTriggerOptions = [ + { label: 'Conversation Created', id: 'intercom_conversation_created' }, + { label: 'Conversation Reply', id: 'intercom_conversation_reply' }, + { label: 'Conversation Closed', id: 'intercom_conversation_closed' }, + { label: 'Contact Created', id: 'intercom_contact_created' }, + { label: 'User Created', id: 'intercom_user_created' }, + { label: 'All Events', id: 'intercom_webhook' }, +] + +/** + * Generates HTML setup instructions for Intercom webhook triggers. + */ +export function intercomSetupInstructions(eventType: string): string { + const instructions = [ + 'Copy the Webhook URL above.', + 'Go to your Intercom Developer Hub.', + 'Select your app, then go to Webhooks.', + 'Paste the webhook URL into the Endpoint URL field.', + `Select the ${eventType} topic(s).`, + "Copy your app's Client Secret from the app's Basic Information page and paste it into the Webhook Secret field above (recommended for security).", + 'Save the webhook configuration.', + 'Deploy your workflow to activate the trigger.', + ] + + return instructions + .map( + (instruction, index) => + `
${index + 1}. ${instruction}
` + ) + .join('') +} + +/** + * Extra fields for Intercom triggers (webhook secret for signature verification). + */ +export function buildIntercomExtraFields(triggerId: string): SubBlockConfig[] { + return [ + { + id: 'webhookSecret', + title: 'Webhook Secret', + type: 'short-input', + placeholder: 'Enter your Intercom app Client Secret', + description: + "Your app's Client Secret from the Developer Hub. Used to verify webhook authenticity via X-Hub-Signature.", + password: true, + mode: 'trigger', + condition: { field: 'selectedTriggerId', value: triggerId }, + }, + ] +} + +/** + * Maps trigger IDs to the Intercom webhook topics they should match. + */ +export const INTERCOM_TRIGGER_TOPIC_MAP: Record = { + intercom_conversation_created: ['conversation.user.created', 'conversation.admin.single.created'], + intercom_conversation_reply: ['conversation.user.replied', 'conversation.admin.replied'], + intercom_conversation_closed: ['conversation.admin.closed'], + intercom_contact_created: ['contact.created'], + intercom_user_created: ['user.created'], + intercom_webhook: [], // Empty = accept all events +} + +/** + * Checks if an Intercom webhook event matches the configured trigger. + */ +export function isIntercomEventMatch(triggerId: string, topic: string): boolean { + const allowedTopics = INTERCOM_TRIGGER_TOPIC_MAP[triggerId] + if (!allowedTopics || allowedTopics.length === 0) { + return true + } + return allowedTopics.includes(topic) +} + +/** + * Build outputs for Intercom conversation triggers. + */ +export function buildIntercomConversationOutputs(): Record { + return { + topic: { type: 'string', description: 'The webhook topic (e.g., conversation.user.created)' }, + id: { type: 'string', description: 'Unique notification ID' }, + app_id: { type: 'string', description: 'Your Intercom app ID' }, + created_at: { type: 'number', description: 'Unix timestamp when the event occurred' }, + delivery_attempts: { + type: 'number', + description: 'Number of delivery attempts for this notification', + }, + first_sent_at: { + type: 'number', + description: 'Unix timestamp of first delivery attempt', + }, + data: { + type: 'json', + description: + 'Event data containing the conversation object. Access via data.item for conversation details including id, state, open, assignee, contacts, conversation_parts, tags, and source', + }, + } as Record +} + +/** + * Build outputs for Intercom contact triggers. + */ +export function buildIntercomContactOutputs(): Record { + return { + topic: { type: 'string', description: 'The webhook topic (e.g., contact.created)' }, + id: { type: 'string', description: 'Unique notification ID' }, + app_id: { type: 'string', description: 'Your Intercom app ID' }, + created_at: { type: 'number', description: 'Unix timestamp when the event occurred' }, + delivery_attempts: { + type: 'number', + description: 'Number of delivery attempts for this notification', + }, + first_sent_at: { + type: 'number', + description: 'Unix timestamp of first delivery attempt', + }, + data: { + type: 'json', + description: + 'Event data containing the contact object. Access via data.item for contact details including id, role, email, name, phone, external_id, custom_attributes, location, avatar, tags, companies, and timestamps', + }, + } as Record +} + +/** + * Build outputs for the generic Intercom webhook trigger. + */ +export function buildIntercomGenericOutputs(): Record { + return { + topic: { + type: 'string', + description: + 'The webhook topic (e.g., conversation.user.created, contact.created, company.created, ticket.created)', + }, + id: { type: 'string', description: 'Unique notification ID' }, + app_id: { type: 'string', description: 'Your Intercom app ID' }, + created_at: { type: 'number', description: 'Unix timestamp when the event occurred' }, + delivery_attempts: { + type: 'number', + description: 'Number of delivery attempts for this notification', + }, + first_sent_at: { + type: 'number', + description: 'Unix timestamp of first delivery attempt', + }, + data: { + type: 'json', + description: + 'Event data containing the affected object. Access via data.item for the resource (conversation, contact, company, ticket, etc.)', + }, + } as Record +} diff --git a/apps/sim/triggers/intercom/webhook.ts b/apps/sim/triggers/intercom/webhook.ts new file mode 100644 index 00000000000..ded87c77ca8 --- /dev/null +++ b/apps/sim/triggers/intercom/webhook.ts @@ -0,0 +1,41 @@ +import { IntercomIcon } from '@/components/icons' +import { buildTriggerSubBlocks } from '@/triggers' +import { + buildIntercomExtraFields, + buildIntercomGenericOutputs, + intercomSetupInstructions, + intercomTriggerOptions, +} from '@/triggers/intercom/utils' +import type { TriggerConfig } from '@/triggers/types' + +/** + * Intercom Generic Webhook Trigger + * + * Accepts all Intercom webhook events. + */ +export const intercomWebhookTrigger: TriggerConfig = { + id: 'intercom_webhook', + name: 'Intercom Webhook (All Events)', + provider: 'intercom', + description: 'Trigger workflow on any Intercom webhook event', + version: '1.0.0', + icon: IntercomIcon, + + subBlocks: buildTriggerSubBlocks({ + triggerId: 'intercom_webhook', + triggerOptions: intercomTriggerOptions, + setupInstructions: intercomSetupInstructions( + 'events you want to receive (conversation, contact, user, company, ticket, etc.)' + ), + extraFields: buildIntercomExtraFields('intercom_webhook'), + }), + + outputs: buildIntercomGenericOutputs(), + + webhook: { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + }, +} diff --git a/apps/sim/triggers/registry.ts b/apps/sim/triggers/registry.ts index 4390bfeefff..26cabd095ff 100644 --- a/apps/sim/triggers/registry.ts +++ b/apps/sim/triggers/registry.ts @@ -121,6 +121,14 @@ import { hubspotTicketPropertyChangedTrigger, } from '@/triggers/hubspot' import { imapPollingTrigger } from '@/triggers/imap' +import { + intercomContactCreatedTrigger, + intercomConversationClosedTrigger, + intercomConversationCreatedTrigger, + intercomConversationReplyTrigger, + intercomUserCreatedTrigger, + intercomWebhookTrigger, +} from '@/triggers/intercom' import { jiraIssueCommentedTrigger, jiraIssueCreatedTrigger, @@ -328,4 +336,10 @@ export const TRIGGER_REGISTRY: TriggerRegistry = { hubspot_ticket_deleted: hubspotTicketDeletedTrigger, hubspot_ticket_property_changed: hubspotTicketPropertyChangedTrigger, imap_poller: imapPollingTrigger, + intercom_conversation_created: intercomConversationCreatedTrigger, + intercom_conversation_reply: intercomConversationReplyTrigger, + intercom_conversation_closed: intercomConversationClosedTrigger, + intercom_contact_created: intercomContactCreatedTrigger, + intercom_user_created: intercomUserCreatedTrigger, + intercom_webhook: intercomWebhookTrigger, } From c26f7730ff3108a573222687b3300fbb01b219a3 Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Mon, 6 Apr 2026 11:31:24 -0700 Subject: [PATCH 2/2] fix(triggers): address PR review feedback for Intercom triggers --- apps/sim/triggers/intercom/utils.ts | 70 +++++++++-------------------- 1 file changed, 20 insertions(+), 50 deletions(-) diff --git a/apps/sim/triggers/intercom/utils.ts b/apps/sim/triggers/intercom/utils.ts index e11f9e9a9ad..04ef4b883b2 100644 --- a/apps/sim/triggers/intercom/utils.ts +++ b/apps/sim/triggers/intercom/utils.ts @@ -72,16 +72,17 @@ export const INTERCOM_TRIGGER_TOPIC_MAP: Record = { */ export function isIntercomEventMatch(triggerId: string, topic: string): boolean { const allowedTopics = INTERCOM_TRIGGER_TOPIC_MAP[triggerId] - if (!allowedTopics || allowedTopics.length === 0) { + if (allowedTopics === undefined) return false + if (allowedTopics.length === 0) { return true } return allowedTopics.includes(topic) } /** - * Build outputs for Intercom conversation triggers. + * Shared base outputs for all Intercom webhook triggers. */ -export function buildIntercomConversationOutputs(): Record { +function buildIntercomBaseOutputs(dataDescription: string): Record { return { topic: { type: 'string', description: 'The webhook topic (e.g., conversation.user.created)' }, id: { type: 'string', description: 'Unique notification ID' }, @@ -95,64 +96,33 @@ export function buildIntercomConversationOutputs(): Record } +/** + * Build outputs for Intercom conversation triggers. + */ +export function buildIntercomConversationOutputs(): Record { + return buildIntercomBaseOutputs( + 'Event data containing the conversation object. Access via data.item for conversation details including id, state, open, assignee, contacts, conversation_parts, tags, and source' + ) +} + /** * Build outputs for Intercom contact triggers. */ export function buildIntercomContactOutputs(): Record { - return { - topic: { type: 'string', description: 'The webhook topic (e.g., contact.created)' }, - id: { type: 'string', description: 'Unique notification ID' }, - app_id: { type: 'string', description: 'Your Intercom app ID' }, - created_at: { type: 'number', description: 'Unix timestamp when the event occurred' }, - delivery_attempts: { - type: 'number', - description: 'Number of delivery attempts for this notification', - }, - first_sent_at: { - type: 'number', - description: 'Unix timestamp of first delivery attempt', - }, - data: { - type: 'json', - description: - 'Event data containing the contact object. Access via data.item for contact details including id, role, email, name, phone, external_id, custom_attributes, location, avatar, tags, companies, and timestamps', - }, - } as Record + return buildIntercomBaseOutputs( + 'Event data containing the contact object. Access via data.item for contact details including id, role, email, name, phone, external_id, custom_attributes, location, avatar, tags, companies, and timestamps' + ) } /** * Build outputs for the generic Intercom webhook trigger. */ export function buildIntercomGenericOutputs(): Record { - return { - topic: { - type: 'string', - description: - 'The webhook topic (e.g., conversation.user.created, contact.created, company.created, ticket.created)', - }, - id: { type: 'string', description: 'Unique notification ID' }, - app_id: { type: 'string', description: 'Your Intercom app ID' }, - created_at: { type: 'number', description: 'Unix timestamp when the event occurred' }, - delivery_attempts: { - type: 'number', - description: 'Number of delivery attempts for this notification', - }, - first_sent_at: { - type: 'number', - description: 'Unix timestamp of first delivery attempt', - }, - data: { - type: 'json', - description: - 'Event data containing the affected object. Access via data.item for the resource (conversation, contact, company, ticket, etc.)', - }, - } as Record + return buildIntercomBaseOutputs( + 'Event data containing the affected object. Access via data.item for the resource (conversation, contact, company, ticket, etc.)' + ) }