@workbuddy/piece-workbuddy-vnext 1.0.4 → 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (208) hide show
  1. package/package.json +1 -1
  2. package/src/index.d.ts.map +1 -1
  3. package/src/index.js +89 -83
  4. package/src/index.js.map +1 -1
  5. package/src/index.ts +29 -17
  6. package/src/lib/actions/agents.d.ts.map +1 -1
  7. package/src/lib/actions/agents.js +6 -4
  8. package/src/lib/actions/agents.js.map +1 -1
  9. package/src/lib/actions/agents.ts +8 -4
  10. package/src/lib/actions/attachments.d.ts.map +1 -1
  11. package/src/lib/actions/attachments.js +2 -1
  12. package/src/lib/actions/attachments.js.map +1 -1
  13. package/src/lib/actions/attachments.ts +3 -1
  14. package/src/lib/actions/{crm->-companies.d.ts → crm-companies.d.ts} +1 -1
  15. package/src/lib/actions/crm-companies.d.ts.map +1 -0
  16. package/src/lib/actions/{crm->-companies.js → crm-companies.js} +1 -1
  17. package/src/lib/actions/{crm->-invites.js.map → crm-companies.js.map} +1 -1
  18. package/src/lib/actions/{crm->-contacts.d.ts → crm-contacts.d.ts} +1 -1
  19. package/src/lib/actions/crm-contacts.d.ts.map +1 -0
  20. package/src/lib/actions/{crm->-contacts.js → crm-contacts.js} +1 -1
  21. package/src/lib/actions/crm-contacts.js.map +1 -0
  22. package/src/lib/actions/{crm->-contractors.d.ts → crm-contractors.d.ts} +1 -1
  23. package/src/lib/actions/crm-contractors.d.ts.map +1 -0
  24. package/src/lib/actions/{crm->-contractors.js → crm-contractors.js} +1 -1
  25. package/src/lib/actions/{crm->-employees.js.map → crm-contractors.js.map} +1 -1
  26. package/src/lib/actions/{crm->-customers.d.ts → crm-customers.d.ts} +1 -1
  27. package/src/lib/actions/crm-customers.d.ts.map +1 -0
  28. package/src/lib/actions/{crm->-customers.js → crm-customers.js} +1 -1
  29. package/src/lib/actions/crm-customers.js.map +1 -0
  30. package/src/lib/actions/{crm->-employees.d.ts → crm-employees.d.ts} +1 -1
  31. package/src/lib/actions/crm-employees.d.ts.map +1 -0
  32. package/src/lib/actions/{crm->-employees.js → crm-employees.js} +1 -1
  33. package/src/lib/actions/crm-employees.js.map +1 -0
  34. package/src/lib/actions/{crm->-external-users.d.ts → crm-external-users.d.ts} +1 -1
  35. package/src/lib/actions/crm-external-users.d.ts.map +1 -0
  36. package/src/lib/actions/{crm->-external-users.js → crm-external-users.js} +1 -1
  37. package/src/lib/actions/crm-external-users.js.map +1 -0
  38. package/src/lib/actions/{crm->-invites.d.ts → crm-invites.d.ts} +1 -1
  39. package/src/lib/actions/crm-invites.d.ts.map +1 -0
  40. package/src/lib/actions/{crm->-invites.js → crm-invites.js} +1 -1
  41. package/src/lib/actions/crm-invites.js.map +1 -0
  42. package/src/lib/actions/{crm->-sites.d.ts → crm-sites.d.ts} +1 -1
  43. package/src/lib/actions/crm-sites.d.ts.map +1 -0
  44. package/src/lib/actions/{crm->-sites.js → crm-sites.js} +1 -1
  45. package/src/lib/actions/crm-sites.js.map +1 -0
  46. package/src/lib/actions/{crm->-suppliers.d.ts → crm-suppliers.d.ts} +1 -1
  47. package/src/lib/actions/crm-suppliers.d.ts.map +1 -0
  48. package/src/lib/actions/{crm->-suppliers.js → crm-suppliers.js} +1 -1
  49. package/src/lib/actions/crm-suppliers.js.map +1 -0
  50. package/src/lib/actions/flags.d.ts +34 -0
  51. package/src/lib/actions/flags.d.ts.map +1 -0
  52. package/src/lib/actions/flags.js +185 -0
  53. package/src/lib/actions/flags.js.map +1 -0
  54. package/src/lib/actions/flags.ts +201 -0
  55. package/src/lib/actions/index.d.ts +18 -17
  56. package/src/lib/actions/index.d.ts.map +1 -1
  57. package/src/lib/actions/index.js +18 -17
  58. package/src/lib/actions/index.js.map +1 -1
  59. package/src/lib/actions/index.ts +18 -17
  60. package/src/lib/actions/{jobs->-activities.d.ts → jobs-activities.d.ts} +15 -5
  61. package/src/lib/actions/jobs-activities.d.ts.map +1 -0
  62. package/src/lib/actions/{jobs->-activities.js → jobs-activities.js} +110 -59
  63. package/src/lib/actions/jobs-activities.js.map +1 -0
  64. package/src/lib/actions/{jobs->-activities.ts → jobs-activities.ts} +118 -57
  65. package/src/lib/actions/{jobs->-contacts.d.ts → jobs-contacts.d.ts} +1 -1
  66. package/src/lib/actions/jobs-contacts.d.ts.map +1 -0
  67. package/src/lib/actions/{jobs->-contacts.js → jobs-contacts.js} +5 -5
  68. package/src/lib/actions/jobs-contacts.js.map +1 -0
  69. package/src/lib/actions/{jobs->-contacts.ts → jobs-contacts.ts} +4 -4
  70. package/src/lib/actions/{jobs->-files.d.ts → jobs-files.d.ts} +1 -1
  71. package/src/lib/actions/jobs-files.d.ts.map +1 -0
  72. package/src/lib/actions/{jobs->-files.js → jobs-files.js} +9 -9
  73. package/src/lib/actions/jobs-files.js.map +1 -0
  74. package/src/lib/actions/{jobs->-files.ts → jobs-files.ts} +8 -8
  75. package/src/lib/actions/{jobs->-tasks.d.ts → jobs-tasks.d.ts} +4 -2
  76. package/src/lib/actions/jobs-tasks.d.ts.map +1 -0
  77. package/src/lib/actions/{jobs->-tasks.js → jobs-tasks.js} +61 -37
  78. package/src/lib/actions/jobs-tasks.js.map +1 -0
  79. package/src/lib/actions/{jobs->-tasks.ts → jobs-tasks.ts} +64 -36
  80. package/src/lib/actions/jobs.d.ts +4 -3
  81. package/src/lib/actions/jobs.d.ts.map +1 -1
  82. package/src/lib/actions/jobs.js +90 -72
  83. package/src/lib/actions/jobs.js.map +1 -1
  84. package/src/lib/actions/jobs.ts +94 -72
  85. package/src/lib/actions/mcp.d.ts +1 -1
  86. package/src/lib/actions/mcp.d.ts.map +1 -1
  87. package/src/lib/actions/mcp.js +7 -6
  88. package/src/lib/actions/mcp.js.map +1 -1
  89. package/src/lib/actions/mcp.ts +8 -6
  90. package/src/lib/actions/settings.js +1 -1
  91. package/src/lib/actions/settings.js.map +1 -1
  92. package/src/lib/actions/settings.ts +1 -1
  93. package/src/lib/actions/{stages->-activities.d.ts → stages-activities.d.ts} +24 -5
  94. package/src/lib/actions/stages-activities.d.ts.map +1 -0
  95. package/src/lib/actions/{stages->-activities.js → stages-activities.js} +164 -68
  96. package/src/lib/actions/stages-activities.js.map +1 -0
  97. package/src/lib/actions/{stages->-activities.ts → stages-activities.ts} +172 -66
  98. package/src/lib/actions/{stages->-files.d.ts → stages-files.d.ts} +5 -1
  99. package/src/lib/actions/stages-files.d.ts.map +1 -0
  100. package/src/lib/actions/{stages->-files.js → stages-files.js} +35 -15
  101. package/src/lib/actions/stages-files.js.map +1 -0
  102. package/src/lib/actions/{stages->-files.ts → stages-files.ts} +34 -14
  103. package/src/lib/actions/{stages->-resources.d.ts → stages-resources.d.ts} +1 -1
  104. package/src/lib/actions/stages-resources.d.ts.map +1 -0
  105. package/src/lib/actions/{stages->-resources.js → stages-resources.js} +7 -5
  106. package/src/lib/actions/stages-resources.js.map +1 -0
  107. package/src/lib/actions/{stages->-resources.ts → stages-resources.ts} +8 -4
  108. package/src/lib/actions/{stages->-tasks.d.ts → stages-tasks.d.ts} +8 -2
  109. package/src/lib/actions/stages-tasks.d.ts.map +1 -0
  110. package/src/lib/actions/{stages->-tasks.js → stages-tasks.js} +91 -47
  111. package/src/lib/actions/stages-tasks.js.map +1 -0
  112. package/src/lib/actions/{stages->-tasks.ts → stages-tasks.ts} +94 -46
  113. package/src/lib/actions/stages.d.ts +6 -2
  114. package/src/lib/actions/stages.d.ts.map +1 -1
  115. package/src/lib/actions/stages.js +77 -27
  116. package/src/lib/actions/stages.js.map +1 -1
  117. package/src/lib/actions/stages.ts +88 -27
  118. package/src/lib/actions/webhooks-v2.js +15 -15
  119. package/src/lib/actions/webhooks-v2.js.map +1 -1
  120. package/src/lib/actions/webhooks-v2.ts +15 -15
  121. package/src/lib/auth.js +2 -2
  122. package/src/lib/auth.js.map +1 -1
  123. package/src/lib/auth.ts +2 -2
  124. package/src/lib/triggers/activity.d.ts.map +1 -1
  125. package/src/lib/triggers/activity.js +54 -42
  126. package/src/lib/triggers/activity.js.map +1 -1
  127. package/src/lib/triggers/activity.ts +54 -42
  128. package/src/lib/triggers/bill.d.ts +240 -48
  129. package/src/lib/triggers/bill.d.ts.map +1 -1
  130. package/src/lib/triggers/bill.js +368 -88
  131. package/src/lib/triggers/bill.js.map +1 -1
  132. package/src/lib/triggers/bill.ts +368 -88
  133. package/src/lib/triggers/invoice.d.ts +240 -48
  134. package/src/lib/triggers/invoice.d.ts.map +1 -1
  135. package/src/lib/triggers/invoice.js +368 -88
  136. package/src/lib/triggers/invoice.js.map +1 -1
  137. package/src/lib/triggers/invoice.ts +368 -88
  138. package/src/lib/triggers/job.d.ts +640 -128
  139. package/src/lib/triggers/job.d.ts.map +1 -1
  140. package/src/lib/triggers/job.js +928 -208
  141. package/src/lib/triggers/job.js.map +1 -1
  142. package/src/lib/triggers/job.ts +928 -208
  143. package/src/lib/triggers/lead.d.ts +400 -80
  144. package/src/lib/triggers/lead.d.ts.map +1 -1
  145. package/src/lib/triggers/lead.js +552 -96
  146. package/src/lib/triggers/lead.js.map +1 -1
  147. package/src/lib/triggers/lead.ts +552 -96
  148. package/src/lib/triggers/opportunity.d.ts +320 -64
  149. package/src/lib/triggers/opportunity.d.ts.map +1 -1
  150. package/src/lib/triggers/opportunity.js +456 -88
  151. package/src/lib/triggers/opportunity.js.map +1 -1
  152. package/src/lib/triggers/opportunity.ts +456 -88
  153. package/src/lib/triggers/quote.d.ts +240 -48
  154. package/src/lib/triggers/quote.d.ts.map +1 -1
  155. package/src/lib/triggers/quote.js +368 -88
  156. package/src/lib/triggers/quote.js.map +1 -1
  157. package/src/lib/triggers/quote.ts +368 -88
  158. package/src/lib/triggers/stage.d.ts +480 -96
  159. package/src/lib/triggers/stage.d.ts.map +1 -1
  160. package/src/lib/triggers/stage.js +764 -220
  161. package/src/lib/triggers/stage.js.map +1 -1
  162. package/src/lib/triggers/stage.ts +764 -220
  163. package/src/lib/triggers/task.d.ts +80 -16
  164. package/src/lib/triggers/task.d.ts.map +1 -1
  165. package/src/lib/triggers/task.js +172 -68
  166. package/src/lib/triggers/task.js.map +1 -1
  167. package/src/lib/triggers/task.ts +172 -68
  168. package/src/lib/actions/crm->-companies.d.ts.map +0 -1
  169. package/src/lib/actions/crm->-companies.js.map +0 -1
  170. package/src/lib/actions/crm->-contacts.d.ts.map +0 -1
  171. package/src/lib/actions/crm->-contacts.js.map +0 -1
  172. package/src/lib/actions/crm->-contractors.d.ts.map +0 -1
  173. package/src/lib/actions/crm->-contractors.js.map +0 -1
  174. package/src/lib/actions/crm->-customers.d.ts.map +0 -1
  175. package/src/lib/actions/crm->-customers.js.map +0 -1
  176. package/src/lib/actions/crm->-employees.d.ts.map +0 -1
  177. package/src/lib/actions/crm->-external-users.d.ts.map +0 -1
  178. package/src/lib/actions/crm->-external-users.js.map +0 -1
  179. package/src/lib/actions/crm->-invites.d.ts.map +0 -1
  180. package/src/lib/actions/crm->-sites.d.ts.map +0 -1
  181. package/src/lib/actions/crm->-sites.js.map +0 -1
  182. package/src/lib/actions/crm->-suppliers.d.ts.map +0 -1
  183. package/src/lib/actions/crm->-suppliers.js.map +0 -1
  184. package/src/lib/actions/jobs->-activities.d.ts.map +0 -1
  185. package/src/lib/actions/jobs->-activities.js.map +0 -1
  186. package/src/lib/actions/jobs->-contacts.d.ts.map +0 -1
  187. package/src/lib/actions/jobs->-contacts.js.map +0 -1
  188. package/src/lib/actions/jobs->-files.d.ts.map +0 -1
  189. package/src/lib/actions/jobs->-files.js.map +0 -1
  190. package/src/lib/actions/jobs->-tasks.d.ts.map +0 -1
  191. package/src/lib/actions/jobs->-tasks.js.map +0 -1
  192. package/src/lib/actions/stages->-activities.d.ts.map +0 -1
  193. package/src/lib/actions/stages->-activities.js.map +0 -1
  194. package/src/lib/actions/stages->-files.d.ts.map +0 -1
  195. package/src/lib/actions/stages->-files.js.map +0 -1
  196. package/src/lib/actions/stages->-resources.d.ts.map +0 -1
  197. package/src/lib/actions/stages->-resources.js.map +0 -1
  198. package/src/lib/actions/stages->-tasks.d.ts.map +0 -1
  199. package/src/lib/actions/stages->-tasks.js.map +0 -1
  200. /package/src/lib/actions/{crm->-companies.ts → crm-companies.ts} +0 -0
  201. /package/src/lib/actions/{crm->-contacts.ts → crm-contacts.ts} +0 -0
  202. /package/src/lib/actions/{crm->-contractors.ts → crm-contractors.ts} +0 -0
  203. /package/src/lib/actions/{crm->-customers.ts → crm-customers.ts} +0 -0
  204. /package/src/lib/actions/{crm->-employees.ts → crm-employees.ts} +0 -0
  205. /package/src/lib/actions/{crm->-external-users.ts → crm-external-users.ts} +0 -0
  206. /package/src/lib/actions/{crm->-invites.ts → crm-invites.ts} +0 -0
  207. /package/src/lib/actions/{crm->-sites.ts → crm-sites.ts} +0 -0
  208. /package/src/lib/actions/{crm->-suppliers.ts → crm-suppliers.ts} +0 -0
@@ -8,30 +8,140 @@ export const stage_created_trigger = createTrigger({
8
8
  displayName: 'Stage Created',
9
9
  description: 'Triggered when a new stage is created',
10
10
  props: {
11
- customer: Property.Array({
11
+ customer: Property.MultiSelectDropdown({
12
12
  displayName: 'Filter by Customer',
13
- description: 'Only trigger for specific customer IDs',
13
+ description: 'Only trigger for specific customer',
14
14
  required: false,
15
+ auth: workbuddyAuth,
16
+ refreshers: [],
17
+ options: async ({ auth }) => {
18
+ const authValue = auth as unknown as { props: { baseUrl: string; clientId: string; clientSecret: string } };
19
+ const token = await getAccessToken(authValue);
20
+ const baseUrl = authValue.props.baseUrl;
21
+ const response = await httpClient.sendRequest<{ items: Array<{ id: string; name: string }> }>({
22
+ method: HttpMethod.GET,
23
+ url: `${baseUrl}/api/v2/public/customers`,
24
+ headers: {
25
+ Authorization: `Bearer ${token}`,
26
+ 'X-WorkBuddy-Version': '2026-01',
27
+ },
28
+ });
29
+ const items = response.body?.items || [];
30
+ return {
31
+ options: items.map((item) => ({
32
+ label: item.name,
33
+ value: item.id,
34
+ })),
35
+ };
36
+ },
15
37
  }),
16
- billingCompany: Property.Array({
38
+ billingCompany: Property.MultiSelectDropdown({
17
39
  displayName: 'Filter by Billing Company',
18
- description: 'Only trigger for specific billing company IDs',
40
+ description: 'Only trigger for specific billing company',
19
41
  required: false,
42
+ auth: workbuddyAuth,
43
+ refreshers: [],
44
+ options: async ({ auth }) => {
45
+ const authValue = auth as unknown as { props: { baseUrl: string; clientId: string; clientSecret: string } };
46
+ const token = await getAccessToken(authValue);
47
+ const baseUrl = authValue.props.baseUrl;
48
+ const response = await httpClient.sendRequest<{ items: Array<{ id: string; name: string }> }>({
49
+ method: HttpMethod.GET,
50
+ url: `${baseUrl}/api/v2/public/companies`,
51
+ headers: {
52
+ Authorization: `Bearer ${token}`,
53
+ 'X-WorkBuddy-Version': '2026-01',
54
+ },
55
+ });
56
+ const items = response.body?.items || [];
57
+ return {
58
+ options: items.map((item) => ({
59
+ label: item.name,
60
+ value: item.id,
61
+ })),
62
+ };
63
+ },
20
64
  }),
21
- tag: Property.Array({
65
+ tag: Property.MultiSelectDropdown({
22
66
  displayName: 'Filter by Tags',
23
- description: 'Only trigger for specific tags IDs',
67
+ description: 'Only trigger for specific tags',
24
68
  required: false,
69
+ auth: workbuddyAuth,
70
+ refreshers: [],
71
+ options: async ({ auth }) => {
72
+ const authValue = auth as unknown as { props: { baseUrl: string; clientId: string; clientSecret: string } };
73
+ const token = await getAccessToken(authValue);
74
+ const baseUrl = authValue.props.baseUrl;
75
+ const response = await httpClient.sendRequest<{ items: Array<{ id: string; name: string }> }>({
76
+ method: HttpMethod.GET,
77
+ url: `${baseUrl}/api/v2/public/settings/tags`,
78
+ headers: {
79
+ Authorization: `Bearer ${token}`,
80
+ 'X-WorkBuddy-Version': '2026-01',
81
+ },
82
+ });
83
+ const items = response.body?.items || [];
84
+ return {
85
+ options: items.map((item) => ({
86
+ label: item.name,
87
+ value: item.id,
88
+ })),
89
+ };
90
+ },
25
91
  }),
26
- resource: Property.Array({
92
+ resource: Property.MultiSelectDropdown({
27
93
  displayName: 'Filter by Resource',
28
- description: 'Only trigger for specific resource IDs',
94
+ description: 'Only trigger for specific resource',
29
95
  required: false,
96
+ auth: workbuddyAuth,
97
+ refreshers: [],
98
+ options: async ({ auth }) => {
99
+ const authValue = auth as unknown as { props: { baseUrl: string; clientId: string; clientSecret: string } };
100
+ const token = await getAccessToken(authValue);
101
+ const baseUrl = authValue.props.baseUrl;
102
+ const response = await httpClient.sendRequest<{ items: Array<{ id: string; name: string }> }>({
103
+ method: HttpMethod.GET,
104
+ url: `${baseUrl}/api/v2/public/employees`,
105
+ headers: {
106
+ Authorization: `Bearer ${token}`,
107
+ 'X-WorkBuddy-Version': '2026-01',
108
+ },
109
+ });
110
+ const items = response.body?.items || [];
111
+ return {
112
+ options: items.map((item) => ({
113
+ label: item.name,
114
+ value: item.id,
115
+ })),
116
+ };
117
+ },
30
118
  }),
31
- workCategory: Property.Array({
119
+ workCategory: Property.MultiSelectDropdown({
32
120
  displayName: 'Filter by Work Category',
33
- description: 'Only trigger for specific work category IDs',
121
+ description: 'Only trigger for specific work category',
34
122
  required: false,
123
+ auth: workbuddyAuth,
124
+ refreshers: [],
125
+ options: async ({ auth }) => {
126
+ const authValue = auth as unknown as { props: { baseUrl: string; clientId: string; clientSecret: string } };
127
+ const token = await getAccessToken(authValue);
128
+ const baseUrl = authValue.props.baseUrl;
129
+ const response = await httpClient.sendRequest<{ items: Array<{ id: string; name: string }> }>({
130
+ method: HttpMethod.GET,
131
+ url: `${baseUrl}/api/v2/public/settings/work-types`,
132
+ headers: {
133
+ Authorization: `Bearer ${token}`,
134
+ 'X-WorkBuddy-Version': '2026-01',
135
+ },
136
+ });
137
+ const items = response.body?.items || [];
138
+ return {
139
+ options: items.map((item) => ({
140
+ label: item.name,
141
+ value: item.id,
142
+ })),
143
+ };
144
+ },
35
145
  }),
36
146
  stageStatus: Property.StaticMultiSelectDropdown({
37
147
  displayName: 'Filter by Status',
@@ -47,33 +157,80 @@ export const stage_created_trigger = createTrigger({
47
157
  ],
48
158
  },
49
159
  }),
50
- schedulingTag: Property.Array({
160
+ schedulingTag: Property.MultiSelectDropdown({
51
161
  displayName: 'Filter by Scheduling Tag',
52
- description: 'Only trigger for specific scheduling tag IDs',
162
+ description: 'Only trigger for specific scheduling tag',
53
163
  required: false,
164
+ auth: workbuddyAuth,
165
+ refreshers: [],
166
+ options: async ({ auth }) => {
167
+ const authValue = auth as unknown as { props: { baseUrl: string; clientId: string; clientSecret: string } };
168
+ const token = await getAccessToken(authValue);
169
+ const baseUrl = authValue.props.baseUrl;
170
+ const response = await httpClient.sendRequest<{ items: Array<{ id: string; name: string }> }>({
171
+ method: HttpMethod.GET,
172
+ url: `${baseUrl}/api/v2/public/settings/tags?type=scheduling`,
173
+ headers: {
174
+ Authorization: `Bearer ${token}`,
175
+ 'X-WorkBuddy-Version': '2026-01',
176
+ },
177
+ });
178
+ const items = response.body?.items || [];
179
+ return {
180
+ options: items.map((item) => ({
181
+ label: item.name,
182
+ value: item.id,
183
+ })),
184
+ };
185
+ },
54
186
  }),
55
187
  },
56
188
  sampleData: {
57
- workOrder: {
58
- id: '507f1f77bcf86cd799439011',
59
- name: 'Foundation Work',
60
- workOrderNumber: 'J10001-5039',
61
- jobNumber: 'J10001',
62
- description: 'Sample stage description',
63
- status: 'In Progress',
64
- previousStatus: 'Open',
65
- createdAt: '2026-03-05T10:00:00.000Z',
66
- updatedAt: '2026-03-05T10:00:00.000Z',
67
- startDate: '2026-03-05T08:00:00.000Z',
68
- dueDate: '2026-03-10T17:00:00.000Z',
69
- completedDate: null,
70
- finalisedDate: null,
71
- customer: { id: '507f1f77bcf86cd799439011', name: 'Acme Corp' },
72
- owner: { id: '507f1f77bcf86cd799439011', name: 'John Smith' },
73
- stageOwner: { id: '507f1f77bcf86cd799439011', name: 'Jane Doe' },
189
+ id: 'whd_019ceacb-232b-764f-8dfd-748e1a226de2',
190
+ event: 'Stage Created',
191
+ action: 'create',
192
+ createdAt: '2026-03-14T05:21:47.307Z',
193
+ webhookTimestamp: 1773465707307,
194
+ data: {
195
+ workOrder: {
196
+ id: '507f1f77bcf86cd799439011',
197
+ name: 'Foundation Work',
198
+ workOrderNumber: 'J10001-5039',
199
+ jobNumber: 'J10001',
200
+ description: 'Sample stage description',
201
+ status: 'In Progress',
202
+ previousStatus: 'Open',
203
+ createdAt: '2026-03-05T10:00:00.000Z',
204
+ updatedAt: '2026-03-05T10:00:00.000Z',
205
+ startDate: '2026-03-05T08:00:00.000Z',
206
+ dueDate: '2026-03-10T17:00:00.000Z',
207
+ completedDate: null,
208
+ finalisedDate: null,
209
+ customer: { id: '507f1f77bcf86cd799439011', name: 'Acme Corp' },
210
+ owner: { id: '507f1f77bcf86cd799439011', name: 'John Smith' },
211
+ stageOwner: { id: '507f1f77bcf86cd799439011', name: 'Jane Doe' },
212
+ technician: { id: '507f1f77bcf86cd799439011', name: 'Mike Tech' },
213
+ subcontractor: null,
214
+ priority: { id: '507f1f77bcf86cd799439011', name: 'High' },
215
+ site: {
216
+ id: '507f1f77bcf86cd799439011',
217
+ name: 'Main Office',
218
+ address: {
219
+ street: '123 Main St',
220
+ suburb: 'Sydney',
221
+ state: 'NSW',
222
+ postcode: '2000',
223
+ country: 'Australia',
224
+ formatted: '123 Main St, Sydney NSW 2000',
225
+ },
226
+ },
227
+ workCategory: { id: '507f1f77bcf86cd799439011', name: 'Electrical' },
228
+ labels: [{ id: '507f1f77bcf86cd799439011', name: 'Urgent' }],
229
+ zones: [{ id: '507f1f77bcf86cd799439011', name: 'North' }],
230
+ billingCompany: { id: '507f1f77bcf86cd799439011', name: 'Acme Corp' },
231
+ },
74
232
  technician: { id: '507f1f77bcf86cd799439011', name: 'Mike Tech' },
75
- subcontractor: null,
76
- priority: { id: '507f1f77bcf86cd799439011', name: 'High' },
233
+ billingCompany: { id: '507f1f77bcf86cd799439011', name: 'Acme Corp' },
77
234
  site: {
78
235
  id: '507f1f77bcf86cd799439011',
79
236
  name: 'Main Office',
@@ -86,24 +243,6 @@ export const stage_created_trigger = createTrigger({
86
243
  formatted: '123 Main St, Sydney NSW 2000',
87
244
  },
88
245
  },
89
- workCategory: { id: '507f1f77bcf86cd799439011', name: 'Electrical' },
90
- labels: [{ id: '507f1f77bcf86cd799439011', name: 'Urgent' }],
91
- zones: [{ id: '507f1f77bcf86cd799439011', name: 'North' }],
92
- billingCompany: { id: '507f1f77bcf86cd799439011', name: 'Acme Corp' },
93
- },
94
- technician: { id: '507f1f77bcf86cd799439011', name: 'Mike Tech' },
95
- billingCompany: { id: '507f1f77bcf86cd799439011', name: 'Acme Corp' },
96
- site: {
97
- id: '507f1f77bcf86cd799439011',
98
- name: 'Main Office',
99
- address: {
100
- street: '123 Main St',
101
- suburb: 'Sydney',
102
- state: 'NSW',
103
- postcode: '2000',
104
- country: 'Australia',
105
- formatted: '123 Main St, Sydney NSW 2000',
106
- },
107
246
  },
108
247
  },
109
248
  type: TriggerStrategy.WEBHOOK,
@@ -122,7 +261,7 @@ export const stage_created_trigger = createTrigger({
122
261
  if (context.propsValue.stageStatus?.length)
123
262
  filters.stageStatus = context.propsValue.stageStatus.map((v: string) => JSON.parse(v));
124
263
  if (context.propsValue.schedulingTag?.length) filters.schedulingTag = context.propsValue.schedulingTag;
125
- // Register webhook with WorkBuddy v2 API (server handles upsert - reactivates if exists)
264
+ // Register webhook with WorkBuddy v2 API
126
265
  const response = await httpClient.sendRequest<{ data: { id: string } }>({
127
266
  method: HttpMethod.POST,
128
267
  url: `${baseUrl}/api/v2/public/webhooks`,
@@ -154,18 +293,15 @@ export const stage_created_trigger = createTrigger({
154
293
  const webhookId = await context.store.get<string>('webhookId');
155
294
 
156
295
  if (webhookId) {
157
- // Pause webhook (server keeps it for potential reactivation)
296
+ // Delete webhook to avoid stale subscriptions causing duplicate trigger deliveries
158
297
  await httpClient.sendRequest({
159
- method: HttpMethod.PATCH,
298
+ method: HttpMethod.DELETE,
160
299
  url: `${baseUrl}/api/v2/public/webhooks/${webhookId}`,
161
300
  headers: {
162
301
  Authorization: `Bearer ${token}`,
163
302
  'Content-Type': 'application/json',
164
303
  'X-WorkBuddy-Version': '2026-01',
165
304
  },
166
- body: {
167
- status: 'paused',
168
- },
169
305
  });
170
306
  }
171
307
  },
@@ -181,30 +317,140 @@ export const stage_updated_trigger = createTrigger({
181
317
  displayName: 'Stage Updated',
182
318
  description: 'Triggered when a stage is updated',
183
319
  props: {
184
- customer: Property.Array({
320
+ customer: Property.MultiSelectDropdown({
185
321
  displayName: 'Filter by Customer',
186
- description: 'Only trigger for specific customer IDs',
322
+ description: 'Only trigger for specific customer',
187
323
  required: false,
324
+ auth: workbuddyAuth,
325
+ refreshers: [],
326
+ options: async ({ auth }) => {
327
+ const authValue = auth as unknown as { props: { baseUrl: string; clientId: string; clientSecret: string } };
328
+ const token = await getAccessToken(authValue);
329
+ const baseUrl = authValue.props.baseUrl;
330
+ const response = await httpClient.sendRequest<{ items: Array<{ id: string; name: string }> }>({
331
+ method: HttpMethod.GET,
332
+ url: `${baseUrl}/api/v2/public/customers`,
333
+ headers: {
334
+ Authorization: `Bearer ${token}`,
335
+ 'X-WorkBuddy-Version': '2026-01',
336
+ },
337
+ });
338
+ const items = response.body?.items || [];
339
+ return {
340
+ options: items.map((item) => ({
341
+ label: item.name,
342
+ value: item.id,
343
+ })),
344
+ };
345
+ },
188
346
  }),
189
- billingCompany: Property.Array({
347
+ billingCompany: Property.MultiSelectDropdown({
190
348
  displayName: 'Filter by Billing Company',
191
- description: 'Only trigger for specific billing company IDs',
349
+ description: 'Only trigger for specific billing company',
192
350
  required: false,
351
+ auth: workbuddyAuth,
352
+ refreshers: [],
353
+ options: async ({ auth }) => {
354
+ const authValue = auth as unknown as { props: { baseUrl: string; clientId: string; clientSecret: string } };
355
+ const token = await getAccessToken(authValue);
356
+ const baseUrl = authValue.props.baseUrl;
357
+ const response = await httpClient.sendRequest<{ items: Array<{ id: string; name: string }> }>({
358
+ method: HttpMethod.GET,
359
+ url: `${baseUrl}/api/v2/public/companies`,
360
+ headers: {
361
+ Authorization: `Bearer ${token}`,
362
+ 'X-WorkBuddy-Version': '2026-01',
363
+ },
364
+ });
365
+ const items = response.body?.items || [];
366
+ return {
367
+ options: items.map((item) => ({
368
+ label: item.name,
369
+ value: item.id,
370
+ })),
371
+ };
372
+ },
193
373
  }),
194
- tag: Property.Array({
374
+ tag: Property.MultiSelectDropdown({
195
375
  displayName: 'Filter by Tags',
196
- description: 'Only trigger for specific tags IDs',
376
+ description: 'Only trigger for specific tags',
197
377
  required: false,
378
+ auth: workbuddyAuth,
379
+ refreshers: [],
380
+ options: async ({ auth }) => {
381
+ const authValue = auth as unknown as { props: { baseUrl: string; clientId: string; clientSecret: string } };
382
+ const token = await getAccessToken(authValue);
383
+ const baseUrl = authValue.props.baseUrl;
384
+ const response = await httpClient.sendRequest<{ items: Array<{ id: string; name: string }> }>({
385
+ method: HttpMethod.GET,
386
+ url: `${baseUrl}/api/v2/public/settings/tags`,
387
+ headers: {
388
+ Authorization: `Bearer ${token}`,
389
+ 'X-WorkBuddy-Version': '2026-01',
390
+ },
391
+ });
392
+ const items = response.body?.items || [];
393
+ return {
394
+ options: items.map((item) => ({
395
+ label: item.name,
396
+ value: item.id,
397
+ })),
398
+ };
399
+ },
198
400
  }),
199
- resource: Property.Array({
401
+ resource: Property.MultiSelectDropdown({
200
402
  displayName: 'Filter by Resource',
201
- description: 'Only trigger for specific resource IDs',
403
+ description: 'Only trigger for specific resource',
202
404
  required: false,
405
+ auth: workbuddyAuth,
406
+ refreshers: [],
407
+ options: async ({ auth }) => {
408
+ const authValue = auth as unknown as { props: { baseUrl: string; clientId: string; clientSecret: string } };
409
+ const token = await getAccessToken(authValue);
410
+ const baseUrl = authValue.props.baseUrl;
411
+ const response = await httpClient.sendRequest<{ items: Array<{ id: string; name: string }> }>({
412
+ method: HttpMethod.GET,
413
+ url: `${baseUrl}/api/v2/public/employees`,
414
+ headers: {
415
+ Authorization: `Bearer ${token}`,
416
+ 'X-WorkBuddy-Version': '2026-01',
417
+ },
418
+ });
419
+ const items = response.body?.items || [];
420
+ return {
421
+ options: items.map((item) => ({
422
+ label: item.name,
423
+ value: item.id,
424
+ })),
425
+ };
426
+ },
203
427
  }),
204
- workCategory: Property.Array({
428
+ workCategory: Property.MultiSelectDropdown({
205
429
  displayName: 'Filter by Work Category',
206
- description: 'Only trigger for specific work category IDs',
430
+ description: 'Only trigger for specific work category',
207
431
  required: false,
432
+ auth: workbuddyAuth,
433
+ refreshers: [],
434
+ options: async ({ auth }) => {
435
+ const authValue = auth as unknown as { props: { baseUrl: string; clientId: string; clientSecret: string } };
436
+ const token = await getAccessToken(authValue);
437
+ const baseUrl = authValue.props.baseUrl;
438
+ const response = await httpClient.sendRequest<{ items: Array<{ id: string; name: string }> }>({
439
+ method: HttpMethod.GET,
440
+ url: `${baseUrl}/api/v2/public/settings/work-types`,
441
+ headers: {
442
+ Authorization: `Bearer ${token}`,
443
+ 'X-WorkBuddy-Version': '2026-01',
444
+ },
445
+ });
446
+ const items = response.body?.items || [];
447
+ return {
448
+ options: items.map((item) => ({
449
+ label: item.name,
450
+ value: item.id,
451
+ })),
452
+ };
453
+ },
208
454
  }),
209
455
  stageStatus: Property.StaticMultiSelectDropdown({
210
456
  displayName: 'Filter by Status',
@@ -220,33 +466,80 @@ export const stage_updated_trigger = createTrigger({
220
466
  ],
221
467
  },
222
468
  }),
223
- schedulingTag: Property.Array({
469
+ schedulingTag: Property.MultiSelectDropdown({
224
470
  displayName: 'Filter by Scheduling Tag',
225
- description: 'Only trigger for specific scheduling tag IDs',
471
+ description: 'Only trigger for specific scheduling tag',
226
472
  required: false,
473
+ auth: workbuddyAuth,
474
+ refreshers: [],
475
+ options: async ({ auth }) => {
476
+ const authValue = auth as unknown as { props: { baseUrl: string; clientId: string; clientSecret: string } };
477
+ const token = await getAccessToken(authValue);
478
+ const baseUrl = authValue.props.baseUrl;
479
+ const response = await httpClient.sendRequest<{ items: Array<{ id: string; name: string }> }>({
480
+ method: HttpMethod.GET,
481
+ url: `${baseUrl}/api/v2/public/settings/tags?type=scheduling`,
482
+ headers: {
483
+ Authorization: `Bearer ${token}`,
484
+ 'X-WorkBuddy-Version': '2026-01',
485
+ },
486
+ });
487
+ const items = response.body?.items || [];
488
+ return {
489
+ options: items.map((item) => ({
490
+ label: item.name,
491
+ value: item.id,
492
+ })),
493
+ };
494
+ },
227
495
  }),
228
496
  },
229
497
  sampleData: {
230
- workOrder: {
231
- id: '507f1f77bcf86cd799439011',
232
- name: 'Foundation Work',
233
- workOrderNumber: 'J10001-5039',
234
- jobNumber: 'J10001',
235
- description: 'Sample stage description',
236
- status: 'In Progress',
237
- previousStatus: 'Open',
238
- createdAt: '2026-03-05T10:00:00.000Z',
239
- updatedAt: '2026-03-05T10:00:00.000Z',
240
- startDate: '2026-03-05T08:00:00.000Z',
241
- dueDate: '2026-03-10T17:00:00.000Z',
242
- completedDate: null,
243
- finalisedDate: null,
244
- customer: { id: '507f1f77bcf86cd799439011', name: 'Acme Corp' },
245
- owner: { id: '507f1f77bcf86cd799439011', name: 'John Smith' },
246
- stageOwner: { id: '507f1f77bcf86cd799439011', name: 'Jane Doe' },
498
+ id: 'whd_019ceacb-232b-764f-8dfd-748e1a226de2',
499
+ event: 'Stage Updated',
500
+ action: 'update',
501
+ createdAt: '2026-03-14T05:21:47.307Z',
502
+ webhookTimestamp: 1773465707307,
503
+ data: {
504
+ workOrder: {
505
+ id: '507f1f77bcf86cd799439011',
506
+ name: 'Foundation Work',
507
+ workOrderNumber: 'J10001-5039',
508
+ jobNumber: 'J10001',
509
+ description: 'Sample stage description',
510
+ status: 'In Progress',
511
+ previousStatus: 'Open',
512
+ createdAt: '2026-03-05T10:00:00.000Z',
513
+ updatedAt: '2026-03-05T10:00:00.000Z',
514
+ startDate: '2026-03-05T08:00:00.000Z',
515
+ dueDate: '2026-03-10T17:00:00.000Z',
516
+ completedDate: null,
517
+ finalisedDate: null,
518
+ customer: { id: '507f1f77bcf86cd799439011', name: 'Acme Corp' },
519
+ owner: { id: '507f1f77bcf86cd799439011', name: 'John Smith' },
520
+ stageOwner: { id: '507f1f77bcf86cd799439011', name: 'Jane Doe' },
521
+ technician: { id: '507f1f77bcf86cd799439011', name: 'Mike Tech' },
522
+ subcontractor: null,
523
+ priority: { id: '507f1f77bcf86cd799439011', name: 'High' },
524
+ site: {
525
+ id: '507f1f77bcf86cd799439011',
526
+ name: 'Main Office',
527
+ address: {
528
+ street: '123 Main St',
529
+ suburb: 'Sydney',
530
+ state: 'NSW',
531
+ postcode: '2000',
532
+ country: 'Australia',
533
+ formatted: '123 Main St, Sydney NSW 2000',
534
+ },
535
+ },
536
+ workCategory: { id: '507f1f77bcf86cd799439011', name: 'Electrical' },
537
+ labels: [{ id: '507f1f77bcf86cd799439011', name: 'Urgent' }],
538
+ zones: [{ id: '507f1f77bcf86cd799439011', name: 'North' }],
539
+ billingCompany: { id: '507f1f77bcf86cd799439011', name: 'Acme Corp' },
540
+ },
247
541
  technician: { id: '507f1f77bcf86cd799439011', name: 'Mike Tech' },
248
- subcontractor: null,
249
- priority: { id: '507f1f77bcf86cd799439011', name: 'High' },
542
+ billingCompany: { id: '507f1f77bcf86cd799439011', name: 'Acme Corp' },
250
543
  site: {
251
544
  id: '507f1f77bcf86cd799439011',
252
545
  name: 'Main Office',
@@ -259,24 +552,6 @@ export const stage_updated_trigger = createTrigger({
259
552
  formatted: '123 Main St, Sydney NSW 2000',
260
553
  },
261
554
  },
262
- workCategory: { id: '507f1f77bcf86cd799439011', name: 'Electrical' },
263
- labels: [{ id: '507f1f77bcf86cd799439011', name: 'Urgent' }],
264
- zones: [{ id: '507f1f77bcf86cd799439011', name: 'North' }],
265
- billingCompany: { id: '507f1f77bcf86cd799439011', name: 'Acme Corp' },
266
- },
267
- technician: { id: '507f1f77bcf86cd799439011', name: 'Mike Tech' },
268
- billingCompany: { id: '507f1f77bcf86cd799439011', name: 'Acme Corp' },
269
- site: {
270
- id: '507f1f77bcf86cd799439011',
271
- name: 'Main Office',
272
- address: {
273
- street: '123 Main St',
274
- suburb: 'Sydney',
275
- state: 'NSW',
276
- postcode: '2000',
277
- country: 'Australia',
278
- formatted: '123 Main St, Sydney NSW 2000',
279
- },
280
555
  },
281
556
  },
282
557
  type: TriggerStrategy.WEBHOOK,
@@ -295,7 +570,7 @@ export const stage_updated_trigger = createTrigger({
295
570
  if (context.propsValue.stageStatus?.length)
296
571
  filters.stageStatus = context.propsValue.stageStatus.map((v: string) => JSON.parse(v));
297
572
  if (context.propsValue.schedulingTag?.length) filters.schedulingTag = context.propsValue.schedulingTag;
298
- // Register webhook with WorkBuddy v2 API (server handles upsert - reactivates if exists)
573
+ // Register webhook with WorkBuddy v2 API
299
574
  const response = await httpClient.sendRequest<{ data: { id: string } }>({
300
575
  method: HttpMethod.POST,
301
576
  url: `${baseUrl}/api/v2/public/webhooks`,
@@ -327,18 +602,15 @@ export const stage_updated_trigger = createTrigger({
327
602
  const webhookId = await context.store.get<string>('webhookId');
328
603
 
329
604
  if (webhookId) {
330
- // Pause webhook (server keeps it for potential reactivation)
605
+ // Delete webhook to avoid stale subscriptions causing duplicate trigger deliveries
331
606
  await httpClient.sendRequest({
332
- method: HttpMethod.PATCH,
607
+ method: HttpMethod.DELETE,
333
608
  url: `${baseUrl}/api/v2/public/webhooks/${webhookId}`,
334
609
  headers: {
335
610
  Authorization: `Bearer ${token}`,
336
611
  'Content-Type': 'application/json',
337
612
  'X-WorkBuddy-Version': '2026-01',
338
613
  },
339
- body: {
340
- status: 'paused',
341
- },
342
614
  });
343
615
  }
344
616
  },
@@ -354,30 +626,140 @@ export const stage_status_changed_trigger = createTrigger({
354
626
  displayName: 'Stage Status Changed',
355
627
  description: 'Triggered when a stage status changes',
356
628
  props: {
357
- customer: Property.Array({
629
+ customer: Property.MultiSelectDropdown({
358
630
  displayName: 'Filter by Customer',
359
- description: 'Only trigger for specific customer IDs',
631
+ description: 'Only trigger for specific customer',
360
632
  required: false,
633
+ auth: workbuddyAuth,
634
+ refreshers: [],
635
+ options: async ({ auth }) => {
636
+ const authValue = auth as unknown as { props: { baseUrl: string; clientId: string; clientSecret: string } };
637
+ const token = await getAccessToken(authValue);
638
+ const baseUrl = authValue.props.baseUrl;
639
+ const response = await httpClient.sendRequest<{ items: Array<{ id: string; name: string }> }>({
640
+ method: HttpMethod.GET,
641
+ url: `${baseUrl}/api/v2/public/customers`,
642
+ headers: {
643
+ Authorization: `Bearer ${token}`,
644
+ 'X-WorkBuddy-Version': '2026-01',
645
+ },
646
+ });
647
+ const items = response.body?.items || [];
648
+ return {
649
+ options: items.map((item) => ({
650
+ label: item.name,
651
+ value: item.id,
652
+ })),
653
+ };
654
+ },
361
655
  }),
362
- billingCompany: Property.Array({
656
+ billingCompany: Property.MultiSelectDropdown({
363
657
  displayName: 'Filter by Billing Company',
364
- description: 'Only trigger for specific billing company IDs',
658
+ description: 'Only trigger for specific billing company',
365
659
  required: false,
660
+ auth: workbuddyAuth,
661
+ refreshers: [],
662
+ options: async ({ auth }) => {
663
+ const authValue = auth as unknown as { props: { baseUrl: string; clientId: string; clientSecret: string } };
664
+ const token = await getAccessToken(authValue);
665
+ const baseUrl = authValue.props.baseUrl;
666
+ const response = await httpClient.sendRequest<{ items: Array<{ id: string; name: string }> }>({
667
+ method: HttpMethod.GET,
668
+ url: `${baseUrl}/api/v2/public/companies`,
669
+ headers: {
670
+ Authorization: `Bearer ${token}`,
671
+ 'X-WorkBuddy-Version': '2026-01',
672
+ },
673
+ });
674
+ const items = response.body?.items || [];
675
+ return {
676
+ options: items.map((item) => ({
677
+ label: item.name,
678
+ value: item.id,
679
+ })),
680
+ };
681
+ },
366
682
  }),
367
- tag: Property.Array({
683
+ tag: Property.MultiSelectDropdown({
368
684
  displayName: 'Filter by Tags',
369
- description: 'Only trigger for specific tags IDs',
685
+ description: 'Only trigger for specific tags',
370
686
  required: false,
687
+ auth: workbuddyAuth,
688
+ refreshers: [],
689
+ options: async ({ auth }) => {
690
+ const authValue = auth as unknown as { props: { baseUrl: string; clientId: string; clientSecret: string } };
691
+ const token = await getAccessToken(authValue);
692
+ const baseUrl = authValue.props.baseUrl;
693
+ const response = await httpClient.sendRequest<{ items: Array<{ id: string; name: string }> }>({
694
+ method: HttpMethod.GET,
695
+ url: `${baseUrl}/api/v2/public/settings/tags`,
696
+ headers: {
697
+ Authorization: `Bearer ${token}`,
698
+ 'X-WorkBuddy-Version': '2026-01',
699
+ },
700
+ });
701
+ const items = response.body?.items || [];
702
+ return {
703
+ options: items.map((item) => ({
704
+ label: item.name,
705
+ value: item.id,
706
+ })),
707
+ };
708
+ },
371
709
  }),
372
- resource: Property.Array({
710
+ resource: Property.MultiSelectDropdown({
373
711
  displayName: 'Filter by Resource',
374
- description: 'Only trigger for specific resource IDs',
712
+ description: 'Only trigger for specific resource',
375
713
  required: false,
714
+ auth: workbuddyAuth,
715
+ refreshers: [],
716
+ options: async ({ auth }) => {
717
+ const authValue = auth as unknown as { props: { baseUrl: string; clientId: string; clientSecret: string } };
718
+ const token = await getAccessToken(authValue);
719
+ const baseUrl = authValue.props.baseUrl;
720
+ const response = await httpClient.sendRequest<{ items: Array<{ id: string; name: string }> }>({
721
+ method: HttpMethod.GET,
722
+ url: `${baseUrl}/api/v2/public/employees`,
723
+ headers: {
724
+ Authorization: `Bearer ${token}`,
725
+ 'X-WorkBuddy-Version': '2026-01',
726
+ },
727
+ });
728
+ const items = response.body?.items || [];
729
+ return {
730
+ options: items.map((item) => ({
731
+ label: item.name,
732
+ value: item.id,
733
+ })),
734
+ };
735
+ },
376
736
  }),
377
- workCategory: Property.Array({
737
+ workCategory: Property.MultiSelectDropdown({
378
738
  displayName: 'Filter by Work Category',
379
- description: 'Only trigger for specific work category IDs',
739
+ description: 'Only trigger for specific work category',
380
740
  required: false,
741
+ auth: workbuddyAuth,
742
+ refreshers: [],
743
+ options: async ({ auth }) => {
744
+ const authValue = auth as unknown as { props: { baseUrl: string; clientId: string; clientSecret: string } };
745
+ const token = await getAccessToken(authValue);
746
+ const baseUrl = authValue.props.baseUrl;
747
+ const response = await httpClient.sendRequest<{ items: Array<{ id: string; name: string }> }>({
748
+ method: HttpMethod.GET,
749
+ url: `${baseUrl}/api/v2/public/settings/work-types`,
750
+ headers: {
751
+ Authorization: `Bearer ${token}`,
752
+ 'X-WorkBuddy-Version': '2026-01',
753
+ },
754
+ });
755
+ const items = response.body?.items || [];
756
+ return {
757
+ options: items.map((item) => ({
758
+ label: item.name,
759
+ value: item.id,
760
+ })),
761
+ };
762
+ },
381
763
  }),
382
764
  stageStatus: Property.StaticMultiSelectDropdown({
383
765
  displayName: 'Filter by Status',
@@ -393,33 +775,80 @@ export const stage_status_changed_trigger = createTrigger({
393
775
  ],
394
776
  },
395
777
  }),
396
- schedulingTag: Property.Array({
778
+ schedulingTag: Property.MultiSelectDropdown({
397
779
  displayName: 'Filter by Scheduling Tag',
398
- description: 'Only trigger for specific scheduling tag IDs',
780
+ description: 'Only trigger for specific scheduling tag',
399
781
  required: false,
782
+ auth: workbuddyAuth,
783
+ refreshers: [],
784
+ options: async ({ auth }) => {
785
+ const authValue = auth as unknown as { props: { baseUrl: string; clientId: string; clientSecret: string } };
786
+ const token = await getAccessToken(authValue);
787
+ const baseUrl = authValue.props.baseUrl;
788
+ const response = await httpClient.sendRequest<{ items: Array<{ id: string; name: string }> }>({
789
+ method: HttpMethod.GET,
790
+ url: `${baseUrl}/api/v2/public/settings/tags?type=scheduling`,
791
+ headers: {
792
+ Authorization: `Bearer ${token}`,
793
+ 'X-WorkBuddy-Version': '2026-01',
794
+ },
795
+ });
796
+ const items = response.body?.items || [];
797
+ return {
798
+ options: items.map((item) => ({
799
+ label: item.name,
800
+ value: item.id,
801
+ })),
802
+ };
803
+ },
400
804
  }),
401
805
  },
402
806
  sampleData: {
403
- workOrder: {
404
- id: '507f1f77bcf86cd799439011',
405
- name: 'Foundation Work',
406
- workOrderNumber: 'J10001-5039',
407
- jobNumber: 'J10001',
408
- description: 'Sample stage description',
409
- status: 'In Progress',
410
- previousStatus: 'Open',
411
- createdAt: '2026-03-05T10:00:00.000Z',
412
- updatedAt: '2026-03-05T10:00:00.000Z',
413
- startDate: '2026-03-05T08:00:00.000Z',
414
- dueDate: '2026-03-10T17:00:00.000Z',
415
- completedDate: null,
416
- finalisedDate: null,
417
- customer: { id: '507f1f77bcf86cd799439011', name: 'Acme Corp' },
418
- owner: { id: '507f1f77bcf86cd799439011', name: 'John Smith' },
419
- stageOwner: { id: '507f1f77bcf86cd799439011', name: 'Jane Doe' },
807
+ id: 'whd_019ceacb-232b-764f-8dfd-748e1a226de2',
808
+ event: 'Stage Status Changed',
809
+ action: 'update',
810
+ createdAt: '2026-03-14T05:21:47.307Z',
811
+ webhookTimestamp: 1773465707307,
812
+ data: {
813
+ workOrder: {
814
+ id: '507f1f77bcf86cd799439011',
815
+ name: 'Foundation Work',
816
+ workOrderNumber: 'J10001-5039',
817
+ jobNumber: 'J10001',
818
+ description: 'Sample stage description',
819
+ status: 'In Progress',
820
+ previousStatus: 'Open',
821
+ createdAt: '2026-03-05T10:00:00.000Z',
822
+ updatedAt: '2026-03-05T10:00:00.000Z',
823
+ startDate: '2026-03-05T08:00:00.000Z',
824
+ dueDate: '2026-03-10T17:00:00.000Z',
825
+ completedDate: null,
826
+ finalisedDate: null,
827
+ customer: { id: '507f1f77bcf86cd799439011', name: 'Acme Corp' },
828
+ owner: { id: '507f1f77bcf86cd799439011', name: 'John Smith' },
829
+ stageOwner: { id: '507f1f77bcf86cd799439011', name: 'Jane Doe' },
830
+ technician: { id: '507f1f77bcf86cd799439011', name: 'Mike Tech' },
831
+ subcontractor: null,
832
+ priority: { id: '507f1f77bcf86cd799439011', name: 'High' },
833
+ site: {
834
+ id: '507f1f77bcf86cd799439011',
835
+ name: 'Main Office',
836
+ address: {
837
+ street: '123 Main St',
838
+ suburb: 'Sydney',
839
+ state: 'NSW',
840
+ postcode: '2000',
841
+ country: 'Australia',
842
+ formatted: '123 Main St, Sydney NSW 2000',
843
+ },
844
+ },
845
+ workCategory: { id: '507f1f77bcf86cd799439011', name: 'Electrical' },
846
+ labels: [{ id: '507f1f77bcf86cd799439011', name: 'Urgent' }],
847
+ zones: [{ id: '507f1f77bcf86cd799439011', name: 'North' }],
848
+ billingCompany: { id: '507f1f77bcf86cd799439011', name: 'Acme Corp' },
849
+ },
420
850
  technician: { id: '507f1f77bcf86cd799439011', name: 'Mike Tech' },
421
- subcontractor: null,
422
- priority: { id: '507f1f77bcf86cd799439011', name: 'High' },
851
+ billingCompany: { id: '507f1f77bcf86cd799439011', name: 'Acme Corp' },
423
852
  site: {
424
853
  id: '507f1f77bcf86cd799439011',
425
854
  name: 'Main Office',
@@ -432,24 +861,6 @@ export const stage_status_changed_trigger = createTrigger({
432
861
  formatted: '123 Main St, Sydney NSW 2000',
433
862
  },
434
863
  },
435
- workCategory: { id: '507f1f77bcf86cd799439011', name: 'Electrical' },
436
- labels: [{ id: '507f1f77bcf86cd799439011', name: 'Urgent' }],
437
- zones: [{ id: '507f1f77bcf86cd799439011', name: 'North' }],
438
- billingCompany: { id: '507f1f77bcf86cd799439011', name: 'Acme Corp' },
439
- },
440
- technician: { id: '507f1f77bcf86cd799439011', name: 'Mike Tech' },
441
- billingCompany: { id: '507f1f77bcf86cd799439011', name: 'Acme Corp' },
442
- site: {
443
- id: '507f1f77bcf86cd799439011',
444
- name: 'Main Office',
445
- address: {
446
- street: '123 Main St',
447
- suburb: 'Sydney',
448
- state: 'NSW',
449
- postcode: '2000',
450
- country: 'Australia',
451
- formatted: '123 Main St, Sydney NSW 2000',
452
- },
453
864
  },
454
865
  },
455
866
  type: TriggerStrategy.WEBHOOK,
@@ -468,7 +879,7 @@ export const stage_status_changed_trigger = createTrigger({
468
879
  if (context.propsValue.stageStatus?.length)
469
880
  filters.stageStatus = context.propsValue.stageStatus.map((v: string) => JSON.parse(v));
470
881
  if (context.propsValue.schedulingTag?.length) filters.schedulingTag = context.propsValue.schedulingTag;
471
- // Register webhook with WorkBuddy v2 API (server handles upsert - reactivates if exists)
882
+ // Register webhook with WorkBuddy v2 API
472
883
  const response = await httpClient.sendRequest<{ data: { id: string } }>({
473
884
  method: HttpMethod.POST,
474
885
  url: `${baseUrl}/api/v2/public/webhooks`,
@@ -500,18 +911,15 @@ export const stage_status_changed_trigger = createTrigger({
500
911
  const webhookId = await context.store.get<string>('webhookId');
501
912
 
502
913
  if (webhookId) {
503
- // Pause webhook (server keeps it for potential reactivation)
914
+ // Delete webhook to avoid stale subscriptions causing duplicate trigger deliveries
504
915
  await httpClient.sendRequest({
505
- method: HttpMethod.PATCH,
916
+ method: HttpMethod.DELETE,
506
917
  url: `${baseUrl}/api/v2/public/webhooks/${webhookId}`,
507
918
  headers: {
508
919
  Authorization: `Bearer ${token}`,
509
920
  'Content-Type': 'application/json',
510
921
  'X-WorkBuddy-Version': '2026-01',
511
922
  },
512
- body: {
513
- status: 'paused',
514
- },
515
923
  });
516
924
  }
517
925
  },
@@ -527,30 +935,140 @@ export const stage_deleted_trigger = createTrigger({
527
935
  displayName: 'Stage Deleted',
528
936
  description: 'Triggered when a stage is deleted',
529
937
  props: {
530
- customer: Property.Array({
938
+ customer: Property.MultiSelectDropdown({
531
939
  displayName: 'Filter by Customer',
532
- description: 'Only trigger for specific customer IDs',
940
+ description: 'Only trigger for specific customer',
533
941
  required: false,
942
+ auth: workbuddyAuth,
943
+ refreshers: [],
944
+ options: async ({ auth }) => {
945
+ const authValue = auth as unknown as { props: { baseUrl: string; clientId: string; clientSecret: string } };
946
+ const token = await getAccessToken(authValue);
947
+ const baseUrl = authValue.props.baseUrl;
948
+ const response = await httpClient.sendRequest<{ items: Array<{ id: string; name: string }> }>({
949
+ method: HttpMethod.GET,
950
+ url: `${baseUrl}/api/v2/public/customers`,
951
+ headers: {
952
+ Authorization: `Bearer ${token}`,
953
+ 'X-WorkBuddy-Version': '2026-01',
954
+ },
955
+ });
956
+ const items = response.body?.items || [];
957
+ return {
958
+ options: items.map((item) => ({
959
+ label: item.name,
960
+ value: item.id,
961
+ })),
962
+ };
963
+ },
534
964
  }),
535
- billingCompany: Property.Array({
965
+ billingCompany: Property.MultiSelectDropdown({
536
966
  displayName: 'Filter by Billing Company',
537
- description: 'Only trigger for specific billing company IDs',
967
+ description: 'Only trigger for specific billing company',
538
968
  required: false,
969
+ auth: workbuddyAuth,
970
+ refreshers: [],
971
+ options: async ({ auth }) => {
972
+ const authValue = auth as unknown as { props: { baseUrl: string; clientId: string; clientSecret: string } };
973
+ const token = await getAccessToken(authValue);
974
+ const baseUrl = authValue.props.baseUrl;
975
+ const response = await httpClient.sendRequest<{ items: Array<{ id: string; name: string }> }>({
976
+ method: HttpMethod.GET,
977
+ url: `${baseUrl}/api/v2/public/companies`,
978
+ headers: {
979
+ Authorization: `Bearer ${token}`,
980
+ 'X-WorkBuddy-Version': '2026-01',
981
+ },
982
+ });
983
+ const items = response.body?.items || [];
984
+ return {
985
+ options: items.map((item) => ({
986
+ label: item.name,
987
+ value: item.id,
988
+ })),
989
+ };
990
+ },
539
991
  }),
540
- tag: Property.Array({
992
+ tag: Property.MultiSelectDropdown({
541
993
  displayName: 'Filter by Tags',
542
- description: 'Only trigger for specific tags IDs',
994
+ description: 'Only trigger for specific tags',
543
995
  required: false,
996
+ auth: workbuddyAuth,
997
+ refreshers: [],
998
+ options: async ({ auth }) => {
999
+ const authValue = auth as unknown as { props: { baseUrl: string; clientId: string; clientSecret: string } };
1000
+ const token = await getAccessToken(authValue);
1001
+ const baseUrl = authValue.props.baseUrl;
1002
+ const response = await httpClient.sendRequest<{ items: Array<{ id: string; name: string }> }>({
1003
+ method: HttpMethod.GET,
1004
+ url: `${baseUrl}/api/v2/public/settings/tags`,
1005
+ headers: {
1006
+ Authorization: `Bearer ${token}`,
1007
+ 'X-WorkBuddy-Version': '2026-01',
1008
+ },
1009
+ });
1010
+ const items = response.body?.items || [];
1011
+ return {
1012
+ options: items.map((item) => ({
1013
+ label: item.name,
1014
+ value: item.id,
1015
+ })),
1016
+ };
1017
+ },
544
1018
  }),
545
- resource: Property.Array({
1019
+ resource: Property.MultiSelectDropdown({
546
1020
  displayName: 'Filter by Resource',
547
- description: 'Only trigger for specific resource IDs',
1021
+ description: 'Only trigger for specific resource',
548
1022
  required: false,
1023
+ auth: workbuddyAuth,
1024
+ refreshers: [],
1025
+ options: async ({ auth }) => {
1026
+ const authValue = auth as unknown as { props: { baseUrl: string; clientId: string; clientSecret: string } };
1027
+ const token = await getAccessToken(authValue);
1028
+ const baseUrl = authValue.props.baseUrl;
1029
+ const response = await httpClient.sendRequest<{ items: Array<{ id: string; name: string }> }>({
1030
+ method: HttpMethod.GET,
1031
+ url: `${baseUrl}/api/v2/public/employees`,
1032
+ headers: {
1033
+ Authorization: `Bearer ${token}`,
1034
+ 'X-WorkBuddy-Version': '2026-01',
1035
+ },
1036
+ });
1037
+ const items = response.body?.items || [];
1038
+ return {
1039
+ options: items.map((item) => ({
1040
+ label: item.name,
1041
+ value: item.id,
1042
+ })),
1043
+ };
1044
+ },
549
1045
  }),
550
- workCategory: Property.Array({
1046
+ workCategory: Property.MultiSelectDropdown({
551
1047
  displayName: 'Filter by Work Category',
552
- description: 'Only trigger for specific work category IDs',
1048
+ description: 'Only trigger for specific work category',
553
1049
  required: false,
1050
+ auth: workbuddyAuth,
1051
+ refreshers: [],
1052
+ options: async ({ auth }) => {
1053
+ const authValue = auth as unknown as { props: { baseUrl: string; clientId: string; clientSecret: string } };
1054
+ const token = await getAccessToken(authValue);
1055
+ const baseUrl = authValue.props.baseUrl;
1056
+ const response = await httpClient.sendRequest<{ items: Array<{ id: string; name: string }> }>({
1057
+ method: HttpMethod.GET,
1058
+ url: `${baseUrl}/api/v2/public/settings/work-types`,
1059
+ headers: {
1060
+ Authorization: `Bearer ${token}`,
1061
+ 'X-WorkBuddy-Version': '2026-01',
1062
+ },
1063
+ });
1064
+ const items = response.body?.items || [];
1065
+ return {
1066
+ options: items.map((item) => ({
1067
+ label: item.name,
1068
+ value: item.id,
1069
+ })),
1070
+ };
1071
+ },
554
1072
  }),
555
1073
  stageStatus: Property.StaticMultiSelectDropdown({
556
1074
  displayName: 'Filter by Status',
@@ -566,33 +1084,80 @@ export const stage_deleted_trigger = createTrigger({
566
1084
  ],
567
1085
  },
568
1086
  }),
569
- schedulingTag: Property.Array({
1087
+ schedulingTag: Property.MultiSelectDropdown({
570
1088
  displayName: 'Filter by Scheduling Tag',
571
- description: 'Only trigger for specific scheduling tag IDs',
1089
+ description: 'Only trigger for specific scheduling tag',
572
1090
  required: false,
1091
+ auth: workbuddyAuth,
1092
+ refreshers: [],
1093
+ options: async ({ auth }) => {
1094
+ const authValue = auth as unknown as { props: { baseUrl: string; clientId: string; clientSecret: string } };
1095
+ const token = await getAccessToken(authValue);
1096
+ const baseUrl = authValue.props.baseUrl;
1097
+ const response = await httpClient.sendRequest<{ items: Array<{ id: string; name: string }> }>({
1098
+ method: HttpMethod.GET,
1099
+ url: `${baseUrl}/api/v2/public/settings/tags?type=scheduling`,
1100
+ headers: {
1101
+ Authorization: `Bearer ${token}`,
1102
+ 'X-WorkBuddy-Version': '2026-01',
1103
+ },
1104
+ });
1105
+ const items = response.body?.items || [];
1106
+ return {
1107
+ options: items.map((item) => ({
1108
+ label: item.name,
1109
+ value: item.id,
1110
+ })),
1111
+ };
1112
+ },
573
1113
  }),
574
1114
  },
575
1115
  sampleData: {
576
- workOrder: {
577
- id: '507f1f77bcf86cd799439011',
578
- name: 'Foundation Work',
579
- workOrderNumber: 'J10001-5039',
580
- jobNumber: 'J10001',
581
- description: 'Sample stage description',
582
- status: 'In Progress',
583
- previousStatus: 'Open',
584
- createdAt: '2026-03-05T10:00:00.000Z',
585
- updatedAt: '2026-03-05T10:00:00.000Z',
586
- startDate: '2026-03-05T08:00:00.000Z',
587
- dueDate: '2026-03-10T17:00:00.000Z',
588
- completedDate: null,
589
- finalisedDate: null,
590
- customer: { id: '507f1f77bcf86cd799439011', name: 'Acme Corp' },
591
- owner: { id: '507f1f77bcf86cd799439011', name: 'John Smith' },
592
- stageOwner: { id: '507f1f77bcf86cd799439011', name: 'Jane Doe' },
1116
+ id: 'whd_019ceacb-232b-764f-8dfd-748e1a226de2',
1117
+ event: 'Stage Deleted',
1118
+ action: 'remove',
1119
+ createdAt: '2026-03-14T05:21:47.307Z',
1120
+ webhookTimestamp: 1773465707307,
1121
+ data: {
1122
+ workOrder: {
1123
+ id: '507f1f77bcf86cd799439011',
1124
+ name: 'Foundation Work',
1125
+ workOrderNumber: 'J10001-5039',
1126
+ jobNumber: 'J10001',
1127
+ description: 'Sample stage description',
1128
+ status: 'In Progress',
1129
+ previousStatus: 'Open',
1130
+ createdAt: '2026-03-05T10:00:00.000Z',
1131
+ updatedAt: '2026-03-05T10:00:00.000Z',
1132
+ startDate: '2026-03-05T08:00:00.000Z',
1133
+ dueDate: '2026-03-10T17:00:00.000Z',
1134
+ completedDate: null,
1135
+ finalisedDate: null,
1136
+ customer: { id: '507f1f77bcf86cd799439011', name: 'Acme Corp' },
1137
+ owner: { id: '507f1f77bcf86cd799439011', name: 'John Smith' },
1138
+ stageOwner: { id: '507f1f77bcf86cd799439011', name: 'Jane Doe' },
1139
+ technician: { id: '507f1f77bcf86cd799439011', name: 'Mike Tech' },
1140
+ subcontractor: null,
1141
+ priority: { id: '507f1f77bcf86cd799439011', name: 'High' },
1142
+ site: {
1143
+ id: '507f1f77bcf86cd799439011',
1144
+ name: 'Main Office',
1145
+ address: {
1146
+ street: '123 Main St',
1147
+ suburb: 'Sydney',
1148
+ state: 'NSW',
1149
+ postcode: '2000',
1150
+ country: 'Australia',
1151
+ formatted: '123 Main St, Sydney NSW 2000',
1152
+ },
1153
+ },
1154
+ workCategory: { id: '507f1f77bcf86cd799439011', name: 'Electrical' },
1155
+ labels: [{ id: '507f1f77bcf86cd799439011', name: 'Urgent' }],
1156
+ zones: [{ id: '507f1f77bcf86cd799439011', name: 'North' }],
1157
+ billingCompany: { id: '507f1f77bcf86cd799439011', name: 'Acme Corp' },
1158
+ },
593
1159
  technician: { id: '507f1f77bcf86cd799439011', name: 'Mike Tech' },
594
- subcontractor: null,
595
- priority: { id: '507f1f77bcf86cd799439011', name: 'High' },
1160
+ billingCompany: { id: '507f1f77bcf86cd799439011', name: 'Acme Corp' },
596
1161
  site: {
597
1162
  id: '507f1f77bcf86cd799439011',
598
1163
  name: 'Main Office',
@@ -605,24 +1170,6 @@ export const stage_deleted_trigger = createTrigger({
605
1170
  formatted: '123 Main St, Sydney NSW 2000',
606
1171
  },
607
1172
  },
608
- workCategory: { id: '507f1f77bcf86cd799439011', name: 'Electrical' },
609
- labels: [{ id: '507f1f77bcf86cd799439011', name: 'Urgent' }],
610
- zones: [{ id: '507f1f77bcf86cd799439011', name: 'North' }],
611
- billingCompany: { id: '507f1f77bcf86cd799439011', name: 'Acme Corp' },
612
- },
613
- technician: { id: '507f1f77bcf86cd799439011', name: 'Mike Tech' },
614
- billingCompany: { id: '507f1f77bcf86cd799439011', name: 'Acme Corp' },
615
- site: {
616
- id: '507f1f77bcf86cd799439011',
617
- name: 'Main Office',
618
- address: {
619
- street: '123 Main St',
620
- suburb: 'Sydney',
621
- state: 'NSW',
622
- postcode: '2000',
623
- country: 'Australia',
624
- formatted: '123 Main St, Sydney NSW 2000',
625
- },
626
1173
  },
627
1174
  },
628
1175
  type: TriggerStrategy.WEBHOOK,
@@ -641,7 +1188,7 @@ export const stage_deleted_trigger = createTrigger({
641
1188
  if (context.propsValue.stageStatus?.length)
642
1189
  filters.stageStatus = context.propsValue.stageStatus.map((v: string) => JSON.parse(v));
643
1190
  if (context.propsValue.schedulingTag?.length) filters.schedulingTag = context.propsValue.schedulingTag;
644
- // Register webhook with WorkBuddy v2 API (server handles upsert - reactivates if exists)
1191
+ // Register webhook with WorkBuddy v2 API
645
1192
  const response = await httpClient.sendRequest<{ data: { id: string } }>({
646
1193
  method: HttpMethod.POST,
647
1194
  url: `${baseUrl}/api/v2/public/webhooks`,
@@ -673,18 +1220,15 @@ export const stage_deleted_trigger = createTrigger({
673
1220
  const webhookId = await context.store.get<string>('webhookId');
674
1221
 
675
1222
  if (webhookId) {
676
- // Pause webhook (server keeps it for potential reactivation)
1223
+ // Delete webhook to avoid stale subscriptions causing duplicate trigger deliveries
677
1224
  await httpClient.sendRequest({
678
- method: HttpMethod.PATCH,
1225
+ method: HttpMethod.DELETE,
679
1226
  url: `${baseUrl}/api/v2/public/webhooks/${webhookId}`,
680
1227
  headers: {
681
1228
  Authorization: `Bearer ${token}`,
682
1229
  'Content-Type': 'application/json',
683
1230
  'X-WorkBuddy-Version': '2026-01',
684
1231
  },
685
- body: {
686
- status: 'paused',
687
- },
688
1232
  });
689
1233
  }
690
1234
  },