Skip to content

Commit c9b45f4

Browse files
authored
feat(triggers): add HubSpot merge, restore, and generic webhook triggers (#3983)
* feat(triggers): add HubSpot merge, restore, and generic webhook triggers * fix(triggers): add mergedObjectIds to merge trigger output schemas * fix(triggers): derive correct OAuth scope per HubSpot object type in setup instructions * lint
1 parent 925be3d commit c9b45f4

File tree

13 files changed

+2172
-1
lines changed

13 files changed

+2172
-1
lines changed

apps/sim/blocks/blocks/hubspot.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -985,22 +985,31 @@ Return ONLY the JSON array of property names - no explanations, no markdown, no
985985
},
986986
...getTrigger('hubspot_contact_created').subBlocks.slice(1),
987987
...getTrigger('hubspot_contact_deleted').subBlocks.slice(1),
988+
...getTrigger('hubspot_contact_merged').subBlocks.slice(1),
988989
...getTrigger('hubspot_contact_privacy_deleted').subBlocks.slice(1),
989990
...getTrigger('hubspot_contact_property_changed').subBlocks.slice(1),
991+
...getTrigger('hubspot_contact_restored').subBlocks.slice(1),
990992
...getTrigger('hubspot_company_created').subBlocks.slice(1),
991993
...getTrigger('hubspot_company_deleted').subBlocks.slice(1),
994+
...getTrigger('hubspot_company_merged').subBlocks.slice(1),
992995
...getTrigger('hubspot_company_property_changed').subBlocks.slice(1),
996+
...getTrigger('hubspot_company_restored').subBlocks.slice(1),
993997
...getTrigger('hubspot_conversation_creation').subBlocks.slice(1),
994998
...getTrigger('hubspot_conversation_deletion').subBlocks.slice(1),
995999
...getTrigger('hubspot_conversation_new_message').subBlocks.slice(1),
9961000
...getTrigger('hubspot_conversation_privacy_deletion').subBlocks.slice(1),
9971001
...getTrigger('hubspot_conversation_property_changed').subBlocks.slice(1),
9981002
...getTrigger('hubspot_deal_created').subBlocks.slice(1),
9991003
...getTrigger('hubspot_deal_deleted').subBlocks.slice(1),
1004+
...getTrigger('hubspot_deal_merged').subBlocks.slice(1),
10001005
...getTrigger('hubspot_deal_property_changed').subBlocks.slice(1),
1006+
...getTrigger('hubspot_deal_restored').subBlocks.slice(1),
10011007
...getTrigger('hubspot_ticket_created').subBlocks.slice(1),
10021008
...getTrigger('hubspot_ticket_deleted').subBlocks.slice(1),
1009+
...getTrigger('hubspot_ticket_merged').subBlocks.slice(1),
10031010
...getTrigger('hubspot_ticket_property_changed').subBlocks.slice(1),
1011+
...getTrigger('hubspot_ticket_restored').subBlocks.slice(1),
1012+
...getTrigger('hubspot_webhook').subBlocks.slice(1),
10041013
],
10051014
tools: {
10061015
access: [
@@ -1329,22 +1338,31 @@ Return ONLY the JSON array of property names - no explanations, no markdown, no
13291338
available: [
13301339
'hubspot_contact_created',
13311340
'hubspot_contact_deleted',
1341+
'hubspot_contact_merged',
13321342
'hubspot_contact_privacy_deleted',
13331343
'hubspot_contact_property_changed',
1344+
'hubspot_contact_restored',
13341345
'hubspot_company_created',
13351346
'hubspot_company_deleted',
1347+
'hubspot_company_merged',
13361348
'hubspot_company_property_changed',
1349+
'hubspot_company_restored',
13371350
'hubspot_conversation_creation',
13381351
'hubspot_conversation_deletion',
13391352
'hubspot_conversation_new_message',
13401353
'hubspot_conversation_privacy_deletion',
13411354
'hubspot_conversation_property_changed',
13421355
'hubspot_deal_created',
13431356
'hubspot_deal_deleted',
1357+
'hubspot_deal_merged',
13441358
'hubspot_deal_property_changed',
1359+
'hubspot_deal_restored',
13451360
'hubspot_ticket_created',
13461361
'hubspot_ticket_deleted',
1362+
'hubspot_ticket_merged',
13471363
'hubspot_ticket_property_changed',
1364+
'hubspot_ticket_restored',
1365+
'hubspot_webhook',
13481366
],
13491367
},
13501368
}
Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
import { HubspotIcon } from '@/components/icons'
2+
import {
3+
buildCompanyMergedOutputs,
4+
hubspotCompanyTriggerOptions,
5+
hubspotSetupInstructions,
6+
} from '@/triggers/hubspot/utils'
7+
import type { TriggerConfig } from '@/triggers/types'
8+
9+
export const hubspotCompanyMergedTrigger: TriggerConfig = {
10+
id: 'hubspot_company_merged',
11+
name: 'HubSpot Company Merged',
12+
provider: 'hubspot',
13+
description: 'Trigger workflow when companies are merged in HubSpot',
14+
version: '1.0.0',
15+
icon: HubspotIcon,
16+
17+
subBlocks: [
18+
{
19+
id: 'selectedTriggerId',
20+
title: 'Trigger Type',
21+
type: 'dropdown',
22+
mode: 'trigger',
23+
options: hubspotCompanyTriggerOptions,
24+
value: () => 'hubspot_company_merged',
25+
required: true,
26+
},
27+
{
28+
id: 'clientId',
29+
title: 'Client ID',
30+
type: 'short-input',
31+
placeholder: 'Enter your HubSpot app Client ID',
32+
description: 'Found in your HubSpot app settings under Auth tab',
33+
required: true,
34+
mode: 'trigger',
35+
condition: {
36+
field: 'selectedTriggerId',
37+
value: 'hubspot_company_merged',
38+
},
39+
},
40+
{
41+
id: 'clientSecret',
42+
title: 'Client Secret',
43+
type: 'short-input',
44+
placeholder: 'Enter your HubSpot app Client Secret',
45+
description: 'Found in your HubSpot app settings under Auth tab',
46+
password: true,
47+
required: true,
48+
mode: 'trigger',
49+
condition: {
50+
field: 'selectedTriggerId',
51+
value: 'hubspot_company_merged',
52+
},
53+
},
54+
{
55+
id: 'appId',
56+
title: 'App ID',
57+
type: 'short-input',
58+
placeholder: 'Enter your HubSpot App ID',
59+
description: 'Found in your HubSpot app settings. Used to identify your app.',
60+
required: true,
61+
mode: 'trigger',
62+
condition: {
63+
field: 'selectedTriggerId',
64+
value: 'hubspot_company_merged',
65+
},
66+
},
67+
{
68+
id: 'developerApiKey',
69+
title: 'Developer API Key',
70+
type: 'short-input',
71+
placeholder: 'Enter your HubSpot Developer API Key',
72+
description: 'Used for making API calls to HubSpot. Found in your HubSpot app settings.',
73+
password: true,
74+
required: true,
75+
mode: 'trigger',
76+
condition: {
77+
field: 'selectedTriggerId',
78+
value: 'hubspot_company_merged',
79+
},
80+
},
81+
{
82+
id: 'webhookUrlDisplay',
83+
title: 'Webhook URL',
84+
type: 'short-input',
85+
readOnly: true,
86+
showCopyButton: true,
87+
useWebhookUrl: true,
88+
placeholder: 'Webhook URL will be generated',
89+
description: 'Copy this URL and paste it into your HubSpot app webhook subscription settings',
90+
mode: 'trigger',
91+
condition: {
92+
field: 'selectedTriggerId',
93+
value: 'hubspot_company_merged',
94+
},
95+
},
96+
{
97+
id: 'triggerSave',
98+
title: '',
99+
type: 'trigger-save',
100+
mode: 'trigger',
101+
triggerId: 'hubspot_company_merged',
102+
condition: {
103+
field: 'selectedTriggerId',
104+
value: 'hubspot_company_merged',
105+
},
106+
},
107+
{
108+
id: 'triggerInstructions',
109+
title: 'Setup Instructions',
110+
type: 'text',
111+
defaultValue: hubspotSetupInstructions(
112+
'company.merge',
113+
'The webhook will trigger whenever two companies are merged in your HubSpot account. The objectId will be the winning (primary) company ID.'
114+
),
115+
mode: 'trigger',
116+
condition: {
117+
field: 'selectedTriggerId',
118+
value: 'hubspot_company_merged',
119+
},
120+
},
121+
{
122+
id: 'curlSetWebhookUrl',
123+
title: '1. Set Webhook Target URL',
124+
type: 'code',
125+
language: 'javascript',
126+
value: (params: Record<string, any>) => {
127+
const webhookUrl = params.webhookUrlDisplay || '{YOUR_WEBHOOK_URL_FROM_ABOVE}'
128+
return `curl -X PUT "https://api.hubapi.com/webhooks/v3/{YOUR_APP_ID}/settings?hapikey={YOUR_DEVELOPER_API_KEY}" \\
129+
-H "Content-Type: application/json" \\
130+
-d '{
131+
"targetUrl": "${webhookUrl}",
132+
"throttling": {
133+
"maxConcurrentRequests": 10
134+
}
135+
}'`
136+
},
137+
readOnly: true,
138+
collapsible: true,
139+
defaultCollapsed: true,
140+
showCopyButton: true,
141+
description: 'Run this command to set your webhook URL in HubSpot',
142+
mode: 'trigger',
143+
condition: {
144+
field: 'selectedTriggerId',
145+
value: 'hubspot_company_merged',
146+
},
147+
},
148+
{
149+
id: 'curlCreateSubscription',
150+
title: '2. Create Webhook Subscription',
151+
type: 'code',
152+
language: 'javascript',
153+
defaultValue: `curl -X POST "https://api.hubapi.com/webhooks/v3/{YOUR_APP_ID}/subscriptions?hapikey={YOUR_DEVELOPER_API_KEY}" \\
154+
-H "Content-Type: application/json" \\
155+
-d '{
156+
"eventType": "company.merge",
157+
"active": true
158+
}'`,
159+
readOnly: true,
160+
collapsible: true,
161+
defaultCollapsed: true,
162+
showCopyButton: true,
163+
description: 'Run this command to subscribe to company merge events',
164+
mode: 'trigger',
165+
condition: {
166+
field: 'selectedTriggerId',
167+
value: 'hubspot_company_merged',
168+
},
169+
},
170+
{
171+
id: 'samplePayload',
172+
title: 'Event Payload Example',
173+
type: 'code',
174+
language: 'json',
175+
defaultValue: JSON.stringify(
176+
[
177+
{
178+
eventId: 3181526813,
179+
subscriptionId: 4629974,
180+
portalId: 244315265,
181+
appId: 23608917,
182+
occurredAt: 1762659213730,
183+
subscriptionType: 'company.merge',
184+
attemptNumber: 0,
185+
objectId: 216126906049,
186+
changeFlag: 'MERGED',
187+
changeSource: 'CRM_UI',
188+
sourceId: 'userId:84916424',
189+
mergedObjectIds: [216126906050],
190+
},
191+
],
192+
null,
193+
2
194+
),
195+
readOnly: true,
196+
collapsible: true,
197+
defaultCollapsed: true,
198+
mode: 'trigger',
199+
condition: {
200+
field: 'selectedTriggerId',
201+
value: 'hubspot_company_merged',
202+
},
203+
},
204+
],
205+
206+
outputs: buildCompanyMergedOutputs(),
207+
208+
webhook: {
209+
method: 'POST',
210+
headers: {
211+
'Content-Type': 'application/json',
212+
'X-HubSpot-Signature': 'sha256=...',
213+
'X-HubSpot-Request-Id': 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
214+
'User-Agent': 'HubSpot Webhooks',
215+
},
216+
},
217+
}

0 commit comments

Comments
 (0)