From 9336ea7082401a497dcab768a9da06a06e76349e Mon Sep 17 00:00:00 2001 From: waleed Date: Thu, 15 Jan 2026 20:07:25 -0800 Subject: [PATCH 1/4] fix(webflow): fix collection & site dropdown in webflow triggers --- .../webflow/collection_item_changed.ts | 116 +++++++++++++++++- .../webflow/collection_item_created.ts | 116 +++++++++++++++++- .../webflow/collection_item_deleted.ts | 116 +++++++++++++++++- apps/sim/triggers/webflow/form_submission.ts | 58 ++++++++- 4 files changed, 396 insertions(+), 10 deletions(-) diff --git a/apps/sim/triggers/webflow/collection_item_changed.ts b/apps/sim/triggers/webflow/collection_item_changed.ts index aedeae63ad..fb4428c577 100644 --- a/apps/sim/triggers/webflow/collection_item_changed.ts +++ b/apps/sim/triggers/webflow/collection_item_changed.ts @@ -1,6 +1,10 @@ +import { createLogger } from '@sim/logger' import { WebflowIcon } from '@/components/icons' +import { useSubBlockStore } from '@/stores/workflows/subblock/store' import type { TriggerConfig } from '../types' +const logger = createLogger('webflow-collection-item-changed-trigger') + export const webflowCollectionItemChangedTrigger: TriggerConfig = { id: 'webflow_collection_item_changed', name: 'Collection Item Changed', @@ -38,6 +42,58 @@ export const webflowCollectionItemChangedTrigger: TriggerConfig = { field: 'selectedTriggerId', value: 'webflow_collection_item_changed', }, + fetchOptions: async (blockId: string) => { + const credentialId = useSubBlockStore.getState().getValue(blockId, 'triggerCredentials') as + | string + | null + if (!credentialId) { + throw new Error('No Webflow credential selected') + } + try { + const response = await fetch('/api/tools/webflow/sites', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ credential: credentialId }), + }) + if (!response.ok) { + throw new Error('Failed to fetch Webflow sites') + } + const data = await response.json() + if (data.sites && Array.isArray(data.sites)) { + return data.sites.map((site: { id: string; name: string }) => ({ + id: site.id, + label: site.name, + })) + } + return [] + } catch (error) { + logger.error('Error fetching Webflow sites:', error) + throw error + } + }, + fetchOptionById: async (blockId: string, _subBlockId: string, optionId: string) => { + const credentialId = useSubBlockStore.getState().getValue(blockId, 'triggerCredentials') as + | string + | null + if (!credentialId) return null + try { + const response = await fetch('/api/tools/webflow/sites', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ credential: credentialId, siteId: optionId }), + }) + if (!response.ok) return null + const data = await response.json() + const site = data.sites?.find((s: { id: string }) => s.id === optionId) + if (site) { + return { id: site.id, label: site.name } + } + return null + } catch { + return null + } + }, + dependsOn: ['triggerCredentials'], }, { id: 'collectionId', @@ -52,6 +108,60 @@ export const webflowCollectionItemChangedTrigger: TriggerConfig = { field: 'selectedTriggerId', value: 'webflow_collection_item_changed', }, + fetchOptions: async (blockId: string) => { + const credentialId = useSubBlockStore.getState().getValue(blockId, 'triggerCredentials') as + | string + | null + const siteId = useSubBlockStore.getState().getValue(blockId, 'siteId') as string | null + if (!credentialId || !siteId) { + return [] + } + try { + const response = await fetch('/api/tools/webflow/collections', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ credential: credentialId, siteId }), + }) + if (!response.ok) { + throw new Error('Failed to fetch Webflow collections') + } + const data = await response.json() + if (data.collections && Array.isArray(data.collections)) { + return data.collections.map((collection: { id: string; name: string }) => ({ + id: collection.id, + label: collection.name, + })) + } + return [] + } catch (error) { + logger.error('Error fetching Webflow collections:', error) + throw error + } + }, + fetchOptionById: async (blockId: string, _subBlockId: string, optionId: string) => { + const credentialId = useSubBlockStore.getState().getValue(blockId, 'triggerCredentials') as + | string + | null + const siteId = useSubBlockStore.getState().getValue(blockId, 'siteId') as string | null + if (!credentialId || !siteId) return null + try { + const response = await fetch('/api/tools/webflow/collections', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ credential: credentialId, siteId }), + }) + if (!response.ok) return null + const data = await response.json() + const collection = data.collections?.find((c: { id: string }) => c.id === optionId) + if (collection) { + return { id: collection.id, label: collection.name } + } + return null + } catch { + return null + } + }, + dependsOn: ['triggerCredentials', 'siteId'], }, { id: 'triggerSave', @@ -72,9 +182,9 @@ export const webflowCollectionItemChangedTrigger: TriggerConfig = { type: 'text', defaultValue: [ 'Connect your Webflow account using the "Select Webflow credential" button above.', - 'Enter your Webflow Site ID (found in the site URL or site settings).', - 'Optionally enter a Collection ID to monitor only specific collections.', - 'If no Collection ID is provided, the trigger will fire for items changed in any collection on the site.', + 'Select your Webflow site from the dropdown.', + 'Optionally select a collection to monitor only specific collections.', + 'If no collection is selected, the trigger will fire for items changed in any collection on the site.', 'The webhook will trigger whenever an existing item is updated in the specified collection(s).', 'Make sure your Webflow account has appropriate permissions for the specified site.', ] diff --git a/apps/sim/triggers/webflow/collection_item_created.ts b/apps/sim/triggers/webflow/collection_item_created.ts index 777b74b76f..27926a02b9 100644 --- a/apps/sim/triggers/webflow/collection_item_created.ts +++ b/apps/sim/triggers/webflow/collection_item_created.ts @@ -1,6 +1,10 @@ +import { createLogger } from '@sim/logger' import { WebflowIcon } from '@/components/icons' +import { useSubBlockStore } from '@/stores/workflows/subblock/store' import type { TriggerConfig } from '../types' +const logger = createLogger('webflow-collection-item-created-trigger') + export const webflowCollectionItemCreatedTrigger: TriggerConfig = { id: 'webflow_collection_item_created', name: 'Collection Item Created', @@ -51,6 +55,58 @@ export const webflowCollectionItemCreatedTrigger: TriggerConfig = { field: 'selectedTriggerId', value: 'webflow_collection_item_created', }, + fetchOptions: async (blockId: string) => { + const credentialId = useSubBlockStore.getState().getValue(blockId, 'triggerCredentials') as + | string + | null + if (!credentialId) { + throw new Error('No Webflow credential selected') + } + try { + const response = await fetch('/api/tools/webflow/sites', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ credential: credentialId }), + }) + if (!response.ok) { + throw new Error('Failed to fetch Webflow sites') + } + const data = await response.json() + if (data.sites && Array.isArray(data.sites)) { + return data.sites.map((site: { id: string; name: string }) => ({ + id: site.id, + label: site.name, + })) + } + return [] + } catch (error) { + logger.error('Error fetching Webflow sites:', error) + throw error + } + }, + fetchOptionById: async (blockId: string, _subBlockId: string, optionId: string) => { + const credentialId = useSubBlockStore.getState().getValue(blockId, 'triggerCredentials') as + | string + | null + if (!credentialId) return null + try { + const response = await fetch('/api/tools/webflow/sites', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ credential: credentialId, siteId: optionId }), + }) + if (!response.ok) return null + const data = await response.json() + const site = data.sites?.find((s: { id: string }) => s.id === optionId) + if (site) { + return { id: site.id, label: site.name } + } + return null + } catch { + return null + } + }, + dependsOn: ['triggerCredentials'], }, { id: 'collectionId', @@ -65,6 +121,60 @@ export const webflowCollectionItemCreatedTrigger: TriggerConfig = { field: 'selectedTriggerId', value: 'webflow_collection_item_created', }, + fetchOptions: async (blockId: string) => { + const credentialId = useSubBlockStore.getState().getValue(blockId, 'triggerCredentials') as + | string + | null + const siteId = useSubBlockStore.getState().getValue(blockId, 'siteId') as string | null + if (!credentialId || !siteId) { + return [] + } + try { + const response = await fetch('/api/tools/webflow/collections', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ credential: credentialId, siteId }), + }) + if (!response.ok) { + throw new Error('Failed to fetch Webflow collections') + } + const data = await response.json() + if (data.collections && Array.isArray(data.collections)) { + return data.collections.map((collection: { id: string; name: string }) => ({ + id: collection.id, + label: collection.name, + })) + } + return [] + } catch (error) { + logger.error('Error fetching Webflow collections:', error) + throw error + } + }, + fetchOptionById: async (blockId: string, _subBlockId: string, optionId: string) => { + const credentialId = useSubBlockStore.getState().getValue(blockId, 'triggerCredentials') as + | string + | null + const siteId = useSubBlockStore.getState().getValue(blockId, 'siteId') as string | null + if (!credentialId || !siteId) return null + try { + const response = await fetch('/api/tools/webflow/collections', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ credential: credentialId, siteId }), + }) + if (!response.ok) return null + const data = await response.json() + const collection = data.collections?.find((c: { id: string }) => c.id === optionId) + if (collection) { + return { id: collection.id, label: collection.name } + } + return null + } catch { + return null + } + }, + dependsOn: ['triggerCredentials', 'siteId'], }, { id: 'triggerSave', @@ -85,9 +195,9 @@ export const webflowCollectionItemCreatedTrigger: TriggerConfig = { type: 'text', defaultValue: [ 'Connect your Webflow account using the "Select Webflow credential" button above.', - 'Enter your Webflow Site ID (found in the site URL or site settings).', - 'Optionally enter a Collection ID to monitor only specific collections.', - 'If no Collection ID is provided, the trigger will fire for items created in any collection on the site.', + 'Select your Webflow site from the dropdown.', + 'Optionally select a collection to monitor only specific collections.', + 'If no collection is selected, the trigger will fire for items created in any collection on the site.', 'The webhook will trigger whenever a new item is created in the specified collection(s).', 'Make sure your Webflow account has appropriate permissions for the specified site.', ] diff --git a/apps/sim/triggers/webflow/collection_item_deleted.ts b/apps/sim/triggers/webflow/collection_item_deleted.ts index 60fb2805dc..7d7ccdf5e9 100644 --- a/apps/sim/triggers/webflow/collection_item_deleted.ts +++ b/apps/sim/triggers/webflow/collection_item_deleted.ts @@ -1,6 +1,10 @@ +import { createLogger } from '@sim/logger' import { WebflowIcon } from '@/components/icons' +import { useSubBlockStore } from '@/stores/workflows/subblock/store' import type { TriggerConfig } from '../types' +const logger = createLogger('webflow-collection-item-deleted-trigger') + export const webflowCollectionItemDeletedTrigger: TriggerConfig = { id: 'webflow_collection_item_deleted', name: 'Collection Item Deleted', @@ -38,6 +42,58 @@ export const webflowCollectionItemDeletedTrigger: TriggerConfig = { field: 'selectedTriggerId', value: 'webflow_collection_item_deleted', }, + fetchOptions: async (blockId: string) => { + const credentialId = useSubBlockStore.getState().getValue(blockId, 'triggerCredentials') as + | string + | null + if (!credentialId) { + throw new Error('No Webflow credential selected') + } + try { + const response = await fetch('/api/tools/webflow/sites', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ credential: credentialId }), + }) + if (!response.ok) { + throw new Error('Failed to fetch Webflow sites') + } + const data = await response.json() + if (data.sites && Array.isArray(data.sites)) { + return data.sites.map((site: { id: string; name: string }) => ({ + id: site.id, + label: site.name, + })) + } + return [] + } catch (error) { + logger.error('Error fetching Webflow sites:', error) + throw error + } + }, + fetchOptionById: async (blockId: string, _subBlockId: string, optionId: string) => { + const credentialId = useSubBlockStore.getState().getValue(blockId, 'triggerCredentials') as + | string + | null + if (!credentialId) return null + try { + const response = await fetch('/api/tools/webflow/sites', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ credential: credentialId, siteId: optionId }), + }) + if (!response.ok) return null + const data = await response.json() + const site = data.sites?.find((s: { id: string }) => s.id === optionId) + if (site) { + return { id: site.id, label: site.name } + } + return null + } catch { + return null + } + }, + dependsOn: ['triggerCredentials'], }, { id: 'collectionId', @@ -52,6 +108,60 @@ export const webflowCollectionItemDeletedTrigger: TriggerConfig = { field: 'selectedTriggerId', value: 'webflow_collection_item_deleted', }, + fetchOptions: async (blockId: string) => { + const credentialId = useSubBlockStore.getState().getValue(blockId, 'triggerCredentials') as + | string + | null + const siteId = useSubBlockStore.getState().getValue(blockId, 'siteId') as string | null + if (!credentialId || !siteId) { + return [] + } + try { + const response = await fetch('/api/tools/webflow/collections', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ credential: credentialId, siteId }), + }) + if (!response.ok) { + throw new Error('Failed to fetch Webflow collections') + } + const data = await response.json() + if (data.collections && Array.isArray(data.collections)) { + return data.collections.map((collection: { id: string; name: string }) => ({ + id: collection.id, + label: collection.name, + })) + } + return [] + } catch (error) { + logger.error('Error fetching Webflow collections:', error) + throw error + } + }, + fetchOptionById: async (blockId: string, _subBlockId: string, optionId: string) => { + const credentialId = useSubBlockStore.getState().getValue(blockId, 'triggerCredentials') as + | string + | null + const siteId = useSubBlockStore.getState().getValue(blockId, 'siteId') as string | null + if (!credentialId || !siteId) return null + try { + const response = await fetch('/api/tools/webflow/collections', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ credential: credentialId, siteId }), + }) + if (!response.ok) return null + const data = await response.json() + const collection = data.collections?.find((c: { id: string }) => c.id === optionId) + if (collection) { + return { id: collection.id, label: collection.name } + } + return null + } catch { + return null + } + }, + dependsOn: ['triggerCredentials', 'siteId'], }, { id: 'triggerSave', @@ -72,9 +182,9 @@ export const webflowCollectionItemDeletedTrigger: TriggerConfig = { type: 'text', defaultValue: [ 'Connect your Webflow account using the "Select Webflow credential" button above.', - 'Enter your Webflow Site ID (found in the site URL or site settings).', - 'Optionally enter a Collection ID to monitor only specific collections.', - 'If no Collection ID is provided, the trigger will fire for items deleted in any collection on the site.', + 'Select your Webflow site from the dropdown.', + 'Optionally select a collection to monitor only specific collections.', + 'If no collection is selected, the trigger will fire for items deleted in any collection on the site.', 'The webhook will trigger whenever an item is deleted from the specified collection(s).', 'Note: Once an item is deleted, only minimal information (ID, collection, site) is available.', 'Make sure your Webflow account has appropriate permissions for the specified site.', diff --git a/apps/sim/triggers/webflow/form_submission.ts b/apps/sim/triggers/webflow/form_submission.ts index 1a6c7640ba..973d8d02c4 100644 --- a/apps/sim/triggers/webflow/form_submission.ts +++ b/apps/sim/triggers/webflow/form_submission.ts @@ -1,6 +1,10 @@ +import { createLogger } from '@sim/logger' import { WebflowIcon } from '@/components/icons' +import { useSubBlockStore } from '@/stores/workflows/subblock/store' import type { TriggerConfig } from '../types' +const logger = createLogger('webflow-form-submission-trigger') + export const webflowFormSubmissionTrigger: TriggerConfig = { id: 'webflow_form_submission', name: 'Form Submission', @@ -30,6 +34,58 @@ export const webflowFormSubmissionTrigger: TriggerConfig = { required: true, options: [], mode: 'trigger', + fetchOptions: async (blockId: string) => { + const credentialId = useSubBlockStore.getState().getValue(blockId, 'triggerCredentials') as + | string + | null + if (!credentialId) { + throw new Error('No Webflow credential selected') + } + try { + const response = await fetch('/api/tools/webflow/sites', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ credential: credentialId }), + }) + if (!response.ok) { + throw new Error('Failed to fetch Webflow sites') + } + const data = await response.json() + if (data.sites && Array.isArray(data.sites)) { + return data.sites.map((site: { id: string; name: string }) => ({ + id: site.id, + label: site.name, + })) + } + return [] + } catch (error) { + logger.error('Error fetching Webflow sites:', error) + throw error + } + }, + fetchOptionById: async (blockId: string, _subBlockId: string, optionId: string) => { + const credentialId = useSubBlockStore.getState().getValue(blockId, 'triggerCredentials') as + | string + | null + if (!credentialId) return null + try { + const response = await fetch('/api/tools/webflow/sites', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ credential: credentialId, siteId: optionId }), + }) + if (!response.ok) return null + const data = await response.json() + const site = data.sites?.find((s: { id: string }) => s.id === optionId) + if (site) { + return { id: site.id, label: site.name } + } + return null + } catch { + return null + } + }, + dependsOn: ['triggerCredentials'], }, { id: 'formId', @@ -55,7 +111,7 @@ export const webflowFormSubmissionTrigger: TriggerConfig = { type: 'text', defaultValue: [ 'Connect your Webflow account using the "Select Webflow credential" button above.', - 'Enter your Webflow Site ID (found in the site URL or site settings).', + 'Select your Webflow site from the dropdown.', 'Optionally enter a Form ID to monitor only a specific form.', 'If no Form ID is provided, the trigger will fire for any form submission on the site.', 'The webhook will trigger whenever a form is submitted on the specified site.', From a3d529dea4abaaf3fc83727cc2a3a5bc17ed6a99 Mon Sep 17 00:00:00 2001 From: waleed Date: Thu, 15 Jan 2026 20:15:20 -0800 Subject: [PATCH 2/4] added form submission trigger to webflow --- apps/sim/blocks/blocks/webflow.ts | 1 + apps/sim/lib/webhooks/processor.ts | 14 +++++++++++++ .../lib/webhooks/provider-subscriptions.ts | 8 +------- .../webflow/collection_item_created.ts | 1 + apps/sim/triggers/webflow/form_submission.ts | 20 +++++++++++++++++++ 5 files changed, 37 insertions(+), 7 deletions(-) diff --git a/apps/sim/blocks/blocks/webflow.ts b/apps/sim/blocks/blocks/webflow.ts index cdb55df299..cfc3962574 100644 --- a/apps/sim/blocks/blocks/webflow.ts +++ b/apps/sim/blocks/blocks/webflow.ts @@ -127,6 +127,7 @@ export const WebflowBlock: BlockConfig = { ...getTrigger('webflow_collection_item_created').subBlocks, ...getTrigger('webflow_collection_item_changed').subBlocks, ...getTrigger('webflow_collection_item_deleted').subBlocks, + ...getTrigger('webflow_form_submission').subBlocks, ], tools: { access: [ diff --git a/apps/sim/lib/webhooks/processor.ts b/apps/sim/lib/webhooks/processor.ts index 7a70705d41..1723abb555 100644 --- a/apps/sim/lib/webhooks/processor.ts +++ b/apps/sim/lib/webhooks/processor.ts @@ -251,6 +251,20 @@ export function shouldSkipWebhookEvent(webhook: any, body: any, requestId: strin } } + // Webflow collection filtering - filter by collectionId if configured + if (webhook.provider === 'webflow') { + const configuredCollectionId = providerConfig.collectionId + if (configuredCollectionId) { + const payloadCollectionId = body?.payload?.collectionId || body?.collectionId + if (payloadCollectionId && payloadCollectionId !== configuredCollectionId) { + logger.info( + `[${requestId}] Webflow collection '${payloadCollectionId}' doesn't match configured collection '${configuredCollectionId}' for webhook ${webhook.id}, skipping` + ) + return true + } + } + } + return false } diff --git a/apps/sim/lib/webhooks/provider-subscriptions.ts b/apps/sim/lib/webhooks/provider-subscriptions.ts index dd10973d3c..27b6df624a 100644 --- a/apps/sim/lib/webhooks/provider-subscriptions.ts +++ b/apps/sim/lib/webhooks/provider-subscriptions.ts @@ -1455,13 +1455,7 @@ export async function createWebflowWebhookSubscription( url: notificationUrl, } - if (collectionId && webflowTriggerType.startsWith('collection_item_')) { - requestBody.filter = { - resource_type: 'collection', - resource_id: collectionId, - } - } - + // Note: Webflow API only supports 'filter' for form_submission triggers. if (formId && webflowTriggerType === 'form_submission') { requestBody.filter = { resource_type: 'form', diff --git a/apps/sim/triggers/webflow/collection_item_created.ts b/apps/sim/triggers/webflow/collection_item_created.ts index 27926a02b9..8d114002f4 100644 --- a/apps/sim/triggers/webflow/collection_item_created.ts +++ b/apps/sim/triggers/webflow/collection_item_created.ts @@ -24,6 +24,7 @@ export const webflowCollectionItemCreatedTrigger: TriggerConfig = { { label: 'Collection Item Created', id: 'webflow_collection_item_created' }, { label: 'Collection Item Changed', id: 'webflow_collection_item_changed' }, { label: 'Collection Item Deleted', id: 'webflow_collection_item_deleted' }, + { label: 'Form Submission', id: 'webflow_form_submission' }, ], value: () => 'webflow_collection_item_created', required: true, diff --git a/apps/sim/triggers/webflow/form_submission.ts b/apps/sim/triggers/webflow/form_submission.ts index 973d8d02c4..6802de49be 100644 --- a/apps/sim/triggers/webflow/form_submission.ts +++ b/apps/sim/triggers/webflow/form_submission.ts @@ -24,6 +24,10 @@ export const webflowFormSubmissionTrigger: TriggerConfig = { requiredScopes: [], required: true, mode: 'trigger', + condition: { + field: 'selectedTriggerId', + value: 'webflow_form_submission', + }, }, { id: 'siteId', @@ -34,6 +38,10 @@ export const webflowFormSubmissionTrigger: TriggerConfig = { required: true, options: [], mode: 'trigger', + condition: { + field: 'selectedTriggerId', + value: 'webflow_form_submission', + }, fetchOptions: async (blockId: string) => { const credentialId = useSubBlockStore.getState().getValue(blockId, 'triggerCredentials') as | string @@ -95,6 +103,10 @@ export const webflowFormSubmissionTrigger: TriggerConfig = { description: 'The ID of the specific form to monitor (optional - leave empty for all forms)', required: false, mode: 'trigger', + condition: { + field: 'selectedTriggerId', + value: 'webflow_form_submission', + }, }, { id: 'triggerSave', @@ -103,6 +115,10 @@ export const webflowFormSubmissionTrigger: TriggerConfig = { hideFromPreview: true, mode: 'trigger', triggerId: 'webflow_form_submission', + condition: { + field: 'selectedTriggerId', + value: 'webflow_form_submission', + }, }, { id: 'triggerInstructions', @@ -124,6 +140,10 @@ export const webflowFormSubmissionTrigger: TriggerConfig = { ) .join(''), mode: 'trigger', + condition: { + field: 'selectedTriggerId', + value: 'webflow_form_submission', + }, }, ], From ca7dea18ffb41659538d496fa8e93dcb0f1f32d0 Mon Sep 17 00:00:00 2001 From: waleed Date: Fri, 16 Jan 2026 08:07:52 -0800 Subject: [PATCH 3/4] fix(webflow): added form submission trigger and scope --- apps/sim/lib/auth/auth.ts | 2 +- .../lib/webhooks/provider-subscriptions.ts | 7 ++-- apps/sim/lib/webhooks/utils.server.ts | 38 +++++++++++++++---- apps/sim/triggers/webflow/form_submission.ts | 15 ++++---- 4 files changed, 43 insertions(+), 19 deletions(-) diff --git a/apps/sim/lib/auth/auth.ts b/apps/sim/lib/auth/auth.ts index 250d2311ef..2ad93f88a6 100644 --- a/apps/sim/lib/auth/auth.ts +++ b/apps/sim/lib/auth/auth.ts @@ -1858,7 +1858,7 @@ export const auth = betterAuth({ authorizationUrl: 'https://webflow.com/oauth/authorize', tokenUrl: 'https://api.webflow.com/oauth/access_token', userInfoUrl: 'https://api.webflow.com/v2/token/introspect', - scopes: ['sites:read', 'sites:write', 'cms:read', 'cms:write'], + scopes: ['sites:read', 'sites:write', 'cms:read', 'cms:write', 'forms:read'], responseType: 'code', redirectURI: `${getBaseUrl()}/api/auth/oauth2/callback/webflow`, getUserInfo: async (tokens) => { diff --git a/apps/sim/lib/webhooks/provider-subscriptions.ts b/apps/sim/lib/webhooks/provider-subscriptions.ts index 27b6df624a..6461eb1e25 100644 --- a/apps/sim/lib/webhooks/provider-subscriptions.ts +++ b/apps/sim/lib/webhooks/provider-subscriptions.ts @@ -1400,7 +1400,7 @@ export async function createWebflowWebhookSubscription( ): Promise { try { const { path, providerConfig } = webhookData - const { siteId, triggerId, collectionId, formId } = providerConfig || {} + const { siteId, triggerId, collectionId, formName } = providerConfig || {} if (!siteId) { webflowLogger.warn(`[${requestId}] Missing siteId for Webflow webhook creation.`, { @@ -1456,10 +1456,9 @@ export async function createWebflowWebhookSubscription( } // Note: Webflow API only supports 'filter' for form_submission triggers. - if (formId && webflowTriggerType === 'form_submission') { + if (formName && webflowTriggerType === 'form_submission') { requestBody.filter = { - resource_type: 'form', - resource_id: formId, + name: formName, } } diff --git a/apps/sim/lib/webhooks/utils.server.ts b/apps/sim/lib/webhooks/utils.server.ts index 923cfc6508..168e841bfb 100644 --- a/apps/sim/lib/webhooks/utils.server.ts +++ b/apps/sim/lib/webhooks/utils.server.ts @@ -800,15 +800,39 @@ export async function formatWebhookInput( } if (foundWebhook.provider === 'webflow') { + const providerConfig = (foundWebhook.providerConfig as Record) || {} + const triggerId = providerConfig.triggerId as string | undefined + + // Form submission trigger + if (triggerId === 'webflow_form_submission') { + return { + siteId: body?.siteId || '', + formId: body?.formId || '', + name: body?.name || '', + id: body?.id || '', + submittedAt: body?.submittedAt || '', + data: body?.data || {}, + schema: body?.schema || {}, + formElementId: body?.formElementId || '', + } + } + + // Collection item triggers (created, changed, deleted) + // Webflow uses _cid for collection ID and _id for item ID + const { _cid, _id, ...itemFields } = body || {} return { siteId: body?.siteId || '', - formId: body?.formId || '', - name: body?.name || '', - id: body?.id || '', - submittedAt: body?.submittedAt || '', - data: body?.data || {}, - schema: body?.schema || {}, - formElementId: body?.formElementId || '', + collectionId: _cid || body?.collectionId || '', + payload: { + id: _id || '', + cmsLocaleId: itemFields?.cmsLocaleId || '', + lastPublished: itemFields?.lastPublished || itemFields?.['last-published'] || '', + lastUpdated: itemFields?.lastUpdated || itemFields?.['last-updated'] || '', + createdOn: itemFields?.createdOn || itemFields?.['created-on'] || '', + isArchived: itemFields?.isArchived || itemFields?._archived || false, + isDraft: itemFields?.isDraft || itemFields?._draft || false, + fieldData: itemFields, + }, } } diff --git a/apps/sim/triggers/webflow/form_submission.ts b/apps/sim/triggers/webflow/form_submission.ts index 6802de49be..3e1822dc96 100644 --- a/apps/sim/triggers/webflow/form_submission.ts +++ b/apps/sim/triggers/webflow/form_submission.ts @@ -21,7 +21,7 @@ export const webflowFormSubmissionTrigger: TriggerConfig = { type: 'oauth-input', description: 'This trigger requires webflow credentials to access your account.', serviceId: 'webflow', - requiredScopes: [], + requiredScopes: ['forms:read'], required: true, mode: 'trigger', condition: { @@ -96,11 +96,12 @@ export const webflowFormSubmissionTrigger: TriggerConfig = { dependsOn: ['triggerCredentials'], }, { - id: 'formId', - title: 'Form ID', + id: 'formName', + title: 'Form Name', type: 'short-input', - placeholder: 'form-123abc (optional)', - description: 'The ID of the specific form to monitor (optional - leave empty for all forms)', + placeholder: 'Contact Form (optional)', + description: + 'The name of the specific form to monitor (optional - leave empty for all forms)', required: false, mode: 'trigger', condition: { @@ -128,8 +129,8 @@ export const webflowFormSubmissionTrigger: TriggerConfig = { defaultValue: [ 'Connect your Webflow account using the "Select Webflow credential" button above.', 'Select your Webflow site from the dropdown.', - 'Optionally enter a Form ID to monitor only a specific form.', - 'If no Form ID is provided, the trigger will fire for any form submission on the site.', + 'Optionally enter the Form Name to monitor only a specific form.', + 'If no Form Name is provided, the trigger will fire for any form submission on the site.', 'The webhook will trigger whenever a form is submitted on the specified site.', 'Form data will be included in the payload with all submitted field values.', 'Make sure your Webflow account has appropriate permissions for the specified site.', From e5cdc548999eaba52d31600660db694acef3c5bb Mon Sep 17 00:00:00 2001 From: waleed Date: Fri, 16 Jan 2026 08:10:45 -0800 Subject: [PATCH 4/4] fixed function signatures --- apps/sim/triggers/webflow/collection_item_changed.ts | 4 ++-- apps/sim/triggers/webflow/collection_item_created.ts | 4 ++-- apps/sim/triggers/webflow/collection_item_deleted.ts | 4 ++-- apps/sim/triggers/webflow/form_submission.ts | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/sim/triggers/webflow/collection_item_changed.ts b/apps/sim/triggers/webflow/collection_item_changed.ts index fb4428c577..3b6c580bd3 100644 --- a/apps/sim/triggers/webflow/collection_item_changed.ts +++ b/apps/sim/triggers/webflow/collection_item_changed.ts @@ -42,7 +42,7 @@ export const webflowCollectionItemChangedTrigger: TriggerConfig = { field: 'selectedTriggerId', value: 'webflow_collection_item_changed', }, - fetchOptions: async (blockId: string) => { + fetchOptions: async (blockId: string, _subBlockId: string) => { const credentialId = useSubBlockStore.getState().getValue(blockId, 'triggerCredentials') as | string | null @@ -108,7 +108,7 @@ export const webflowCollectionItemChangedTrigger: TriggerConfig = { field: 'selectedTriggerId', value: 'webflow_collection_item_changed', }, - fetchOptions: async (blockId: string) => { + fetchOptions: async (blockId: string, _subBlockId: string) => { const credentialId = useSubBlockStore.getState().getValue(blockId, 'triggerCredentials') as | string | null diff --git a/apps/sim/triggers/webflow/collection_item_created.ts b/apps/sim/triggers/webflow/collection_item_created.ts index 8d114002f4..2ba0a11b65 100644 --- a/apps/sim/triggers/webflow/collection_item_created.ts +++ b/apps/sim/triggers/webflow/collection_item_created.ts @@ -56,7 +56,7 @@ export const webflowCollectionItemCreatedTrigger: TriggerConfig = { field: 'selectedTriggerId', value: 'webflow_collection_item_created', }, - fetchOptions: async (blockId: string) => { + fetchOptions: async (blockId: string, _subBlockId: string) => { const credentialId = useSubBlockStore.getState().getValue(blockId, 'triggerCredentials') as | string | null @@ -122,7 +122,7 @@ export const webflowCollectionItemCreatedTrigger: TriggerConfig = { field: 'selectedTriggerId', value: 'webflow_collection_item_created', }, - fetchOptions: async (blockId: string) => { + fetchOptions: async (blockId: string, _subBlockId: string) => { const credentialId = useSubBlockStore.getState().getValue(blockId, 'triggerCredentials') as | string | null diff --git a/apps/sim/triggers/webflow/collection_item_deleted.ts b/apps/sim/triggers/webflow/collection_item_deleted.ts index 7d7ccdf5e9..c7568568e8 100644 --- a/apps/sim/triggers/webflow/collection_item_deleted.ts +++ b/apps/sim/triggers/webflow/collection_item_deleted.ts @@ -42,7 +42,7 @@ export const webflowCollectionItemDeletedTrigger: TriggerConfig = { field: 'selectedTriggerId', value: 'webflow_collection_item_deleted', }, - fetchOptions: async (blockId: string) => { + fetchOptions: async (blockId: string, _subBlockId: string) => { const credentialId = useSubBlockStore.getState().getValue(blockId, 'triggerCredentials') as | string | null @@ -108,7 +108,7 @@ export const webflowCollectionItemDeletedTrigger: TriggerConfig = { field: 'selectedTriggerId', value: 'webflow_collection_item_deleted', }, - fetchOptions: async (blockId: string) => { + fetchOptions: async (blockId: string, _subBlockId: string) => { const credentialId = useSubBlockStore.getState().getValue(blockId, 'triggerCredentials') as | string | null diff --git a/apps/sim/triggers/webflow/form_submission.ts b/apps/sim/triggers/webflow/form_submission.ts index 3e1822dc96..89a2d59485 100644 --- a/apps/sim/triggers/webflow/form_submission.ts +++ b/apps/sim/triggers/webflow/form_submission.ts @@ -42,7 +42,7 @@ export const webflowFormSubmissionTrigger: TriggerConfig = { field: 'selectedTriggerId', value: 'webflow_form_submission', }, - fetchOptions: async (blockId: string) => { + fetchOptions: async (blockId: string, _subBlockId: string) => { const credentialId = useSubBlockStore.getState().getValue(blockId, 'triggerCredentials') as | string | null