@wesell/n8n-nodes-confirmx 0.1.0
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.
- package/LICENSE +21 -0
- package/README.md +77 -0
- package/credentials/ConfirmXApi.credentials.d.ts +18 -0
- package/credentials/ConfirmXApi.credentials.js +31 -0
- package/credentials/ConfirmXApi.credentials.js.map +1 -0
- package/credentials/ConfirmXApi.credentials.ts +40 -0
- package/index.d.ts +14 -0
- package/index.js +26 -0
- package/nodes/ConfirmX/ConfirmXAccount.node.d.ts +5 -0
- package/nodes/ConfirmX/ConfirmXAccount.node.js +81 -0
- package/nodes/ConfirmX/ConfirmXAccount.node.js.map +1 -0
- package/nodes/ConfirmX/ConfirmXAccount.node.ts +81 -0
- package/nodes/ConfirmX/ConfirmXConversation.node.d.ts +13 -0
- package/nodes/ConfirmX/ConfirmXConversation.node.js +266 -0
- package/nodes/ConfirmX/ConfirmXConversation.node.js.map +1 -0
- package/nodes/ConfirmX/ConfirmXConversation.node.ts +263 -0
- package/nodes/ConfirmX/ConfirmXMessage.node.d.ts +13 -0
- package/nodes/ConfirmX/ConfirmXMessage.node.js +364 -0
- package/nodes/ConfirmX/ConfirmXMessage.node.js.map +1 -0
- package/nodes/ConfirmX/ConfirmXMessage.node.ts +361 -0
- package/nodes/ConfirmX/ConfirmXShippingZone.node.d.ts +5 -0
- package/nodes/ConfirmX/ConfirmXShippingZone.node.js +100 -0
- package/nodes/ConfirmX/ConfirmXShippingZone.node.js.map +1 -0
- package/nodes/ConfirmX/ConfirmXShippingZone.node.ts +103 -0
- package/nodes/ConfirmX/ConfirmXTemplate.node.d.ts +13 -0
- package/nodes/ConfirmX/ConfirmXTemplate.node.js +310 -0
- package/nodes/ConfirmX/ConfirmXTemplate.node.js.map +1 -0
- package/nodes/ConfirmX/ConfirmXTemplate.node.ts +310 -0
- package/nodes/ConfirmX/ConfirmXTrigger.node.d.ts +29 -0
- package/nodes/ConfirmX/ConfirmXTrigger.node.js +190 -0
- package/nodes/ConfirmX/ConfirmXTrigger.node.js.map +1 -0
- package/nodes/ConfirmX/ConfirmXTrigger.node.ts +245 -0
- package/nodes/ConfirmX/ConfirmXWebhook.node.d.ts +5 -0
- package/nodes/ConfirmX/ConfirmXWebhook.node.js +169 -0
- package/nodes/ConfirmX/ConfirmXWebhook.node.js.map +1 -0
- package/nodes/ConfirmX/ConfirmXWebhook.node.ts +163 -0
- package/nodes/ConfirmX/confirmx.svg +4 -0
- package/package.json +69 -0
- package/transports/http.d.ts +43 -0
- package/transports/http.js +117 -0
- package/transports/http.js.map +1 -0
- package/transports/http.ts +170 -0
- package/transports/signature.d.ts +21 -0
- package/transports/signature.js +50 -0
- package/transports/signature.js.map +1 -0
- package/transports/signature.ts +55 -0
- package/types/api.d.ts +199 -0
- package/types/api.js +21 -0
- package/types/api.js.map +1 -0
- package/types/api.ts +238 -0
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ConfirmXTemplate = void 0;
|
|
4
|
+
const http_1 = require("../../transports/http");
|
|
5
|
+
class ConfirmXTemplate {
|
|
6
|
+
constructor() {
|
|
7
|
+
this.description = {
|
|
8
|
+
displayName: 'ConfirmX Template',
|
|
9
|
+
name: 'confirmXTemplate',
|
|
10
|
+
icon: 'file:confirmx.svg',
|
|
11
|
+
group: ['transform'],
|
|
12
|
+
version: 1,
|
|
13
|
+
subtitle: '={{$parameter["operation"]}}',
|
|
14
|
+
description: 'Manage Meta WhatsApp message templates — list, get, create, delete. Templates must be approved by Meta before use.',
|
|
15
|
+
defaults: { name: 'ConfirmX Template' },
|
|
16
|
+
inputs: ['main'],
|
|
17
|
+
outputs: ['main'],
|
|
18
|
+
credentials: [{ name: 'confirmXApi', required: true }],
|
|
19
|
+
properties: [
|
|
20
|
+
{
|
|
21
|
+
displayName: 'Operation',
|
|
22
|
+
name: 'operation',
|
|
23
|
+
type: 'options',
|
|
24
|
+
noDataExpression: true,
|
|
25
|
+
options: [
|
|
26
|
+
{
|
|
27
|
+
name: 'List',
|
|
28
|
+
value: 'list',
|
|
29
|
+
action: 'List templates',
|
|
30
|
+
description: 'List all WhatsApp message templates for an account. Returns every status — APPROVED, PENDING, REJECTED — with full `components[]`. Requires `accountId`. Use when you need to discover which templates exist before sending or auditing.',
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
name: 'Get',
|
|
34
|
+
value: 'get',
|
|
35
|
+
action: 'Get template',
|
|
36
|
+
description: 'Fetch a single template by name and language. Returns the live `components[]` and current Meta approval status. Requires `accountId`, `name`, and `language`. Use after a `template.status` webhook to inspect the latest version.',
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
name: 'Create',
|
|
40
|
+
value: 'create',
|
|
41
|
+
action: 'Create template',
|
|
42
|
+
description: 'Submit a new template for Meta approval. Returns the new template in PENDING status.',
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
name: 'Delete',
|
|
46
|
+
value: 'delete',
|
|
47
|
+
action: 'Delete template',
|
|
48
|
+
description: 'Permanently delete a template.',
|
|
49
|
+
},
|
|
50
|
+
],
|
|
51
|
+
default: 'list',
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
displayName: 'Account',
|
|
55
|
+
name: 'accountId',
|
|
56
|
+
type: 'resourceLocator',
|
|
57
|
+
default: { mode: 'list', value: '' },
|
|
58
|
+
required: true,
|
|
59
|
+
displayOptions: {
|
|
60
|
+
show: { operation: ['list', 'get', 'create', 'delete'] },
|
|
61
|
+
},
|
|
62
|
+
modes: [
|
|
63
|
+
{
|
|
64
|
+
displayName: 'From List',
|
|
65
|
+
name: 'list',
|
|
66
|
+
type: 'list',
|
|
67
|
+
placeholder: 'Select an account…',
|
|
68
|
+
typeOptions: { searchable: true },
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
displayName: 'By ID',
|
|
72
|
+
name: 'id',
|
|
73
|
+
type: 'string',
|
|
74
|
+
placeholder: 'acc_…',
|
|
75
|
+
},
|
|
76
|
+
],
|
|
77
|
+
typeOptions: {
|
|
78
|
+
loadOptionsMethod: 'getAccounts',
|
|
79
|
+
},
|
|
80
|
+
description: 'WhatsApp account to act on',
|
|
81
|
+
},
|
|
82
|
+
// --- Get / Delete ---
|
|
83
|
+
{
|
|
84
|
+
displayName: 'Name',
|
|
85
|
+
name: 'name',
|
|
86
|
+
type: 'string',
|
|
87
|
+
default: '',
|
|
88
|
+
required: true,
|
|
89
|
+
displayOptions: { show: { operation: ['get', 'delete'] } },
|
|
90
|
+
description: 'Template name (lowercase, snake_case)',
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
displayName: 'Language',
|
|
94
|
+
name: 'language',
|
|
95
|
+
type: 'string',
|
|
96
|
+
default: 'en',
|
|
97
|
+
required: true,
|
|
98
|
+
displayOptions: { show: { operation: ['get', 'delete'] } },
|
|
99
|
+
description: 'Template language code (e.g. en, ar)',
|
|
100
|
+
},
|
|
101
|
+
// --- List ---
|
|
102
|
+
{
|
|
103
|
+
displayName: 'Return All',
|
|
104
|
+
name: 'returnAll',
|
|
105
|
+
type: 'boolean',
|
|
106
|
+
default: false,
|
|
107
|
+
displayOptions: { show: { operation: ['list'] } },
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
displayName: 'Limit',
|
|
111
|
+
name: 'limit',
|
|
112
|
+
type: 'number',
|
|
113
|
+
default: 50,
|
|
114
|
+
typeOptions: { minValue: 1, maxValue: 500 },
|
|
115
|
+
displayOptions: { show: { operation: ['list'], returnAll: [false] } },
|
|
116
|
+
},
|
|
117
|
+
// --- Create ---
|
|
118
|
+
{
|
|
119
|
+
displayName: 'Template Name',
|
|
120
|
+
name: 'createName',
|
|
121
|
+
type: 'string',
|
|
122
|
+
default: '',
|
|
123
|
+
required: true,
|
|
124
|
+
displayOptions: { show: { operation: ['create'] } },
|
|
125
|
+
description: 'Lowercase, snake_case, must match /^[a-z][a-z0-9_]*$/',
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
displayName: 'Language',
|
|
129
|
+
name: 'createLanguage',
|
|
130
|
+
type: 'string',
|
|
131
|
+
default: 'en',
|
|
132
|
+
required: true,
|
|
133
|
+
displayOptions: { show: { operation: ['create'] } },
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
displayName: 'Category',
|
|
137
|
+
name: 'createCategory',
|
|
138
|
+
type: 'options',
|
|
139
|
+
default: 'UTILITY',
|
|
140
|
+
required: true,
|
|
141
|
+
options: [
|
|
142
|
+
{ name: 'Utility', value: 'UTILITY' },
|
|
143
|
+
{ name: 'Marketing', value: 'MARKETING' },
|
|
144
|
+
{ name: 'Authentication', value: 'AUTHENTICATION' },
|
|
145
|
+
],
|
|
146
|
+
displayOptions: { show: { operation: ['create'] } },
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
displayName: 'Header Type',
|
|
150
|
+
name: 'createHeaderType',
|
|
151
|
+
type: 'options',
|
|
152
|
+
default: 'NONE',
|
|
153
|
+
options: [
|
|
154
|
+
{ name: 'None', value: 'NONE' },
|
|
155
|
+
{ name: 'Text', value: 'TEXT' },
|
|
156
|
+
{ name: 'Image', value: 'IMAGE' },
|
|
157
|
+
{ name: 'Video', value: 'VIDEO' },
|
|
158
|
+
{ name: 'Document', value: 'DOCUMENT' },
|
|
159
|
+
],
|
|
160
|
+
displayOptions: { show: { operation: ['create'] } },
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
displayName: 'Header Text',
|
|
164
|
+
name: 'createHeaderText',
|
|
165
|
+
type: 'string',
|
|
166
|
+
default: '',
|
|
167
|
+
displayOptions: {
|
|
168
|
+
show: { operation: ['create'], createHeaderType: ['TEXT'] },
|
|
169
|
+
},
|
|
170
|
+
description: 'Required when header type = TEXT. Supports {{1}}, {{2}}, … placeholders.',
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
displayName: 'Header Samples',
|
|
174
|
+
name: 'createHeaderSamples',
|
|
175
|
+
type: 'string',
|
|
176
|
+
default: '',
|
|
177
|
+
displayOptions: {
|
|
178
|
+
show: { operation: ['create'], createHeaderType: ['TEXT'] },
|
|
179
|
+
},
|
|
180
|
+
description: 'Comma-separated sample values, e.g. "Acme Inc,ConfirmX"',
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
displayName: 'Body Text',
|
|
184
|
+
name: 'createBodyText',
|
|
185
|
+
type: 'string',
|
|
186
|
+
typeOptions: { rows: 4 },
|
|
187
|
+
default: '',
|
|
188
|
+
required: true,
|
|
189
|
+
displayOptions: { show: { operation: ['create'] } },
|
|
190
|
+
description: 'Body text with {{1}}, {{2}}, … placeholders',
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
displayName: 'Body Samples',
|
|
194
|
+
name: 'createBodySamples',
|
|
195
|
+
type: 'string',
|
|
196
|
+
default: '',
|
|
197
|
+
displayOptions: { show: { operation: ['create'] } },
|
|
198
|
+
description: 'Comma-separated sample values',
|
|
199
|
+
},
|
|
200
|
+
{
|
|
201
|
+
displayName: 'Footer Text',
|
|
202
|
+
name: 'createFooterText',
|
|
203
|
+
type: 'string',
|
|
204
|
+
default: '',
|
|
205
|
+
displayOptions: { show: { operation: ['create'] } },
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
displayName: 'Buttons (JSON)',
|
|
209
|
+
name: 'createButtons',
|
|
210
|
+
type: 'json',
|
|
211
|
+
default: '[]',
|
|
212
|
+
displayOptions: { show: { operation: ['create'] } },
|
|
213
|
+
description: 'JSON array of buttons, each `{type:"QUICK_REPLY"|"URL"|"PHONE_NUMBER", text, url?, phone_number?}`. Example: `[{"type":"URL","text":"Track","url":"https://example.com/track/{{1}}"}]`.',
|
|
214
|
+
},
|
|
215
|
+
],
|
|
216
|
+
usableAsTool: true,
|
|
217
|
+
};
|
|
218
|
+
this.methods = {
|
|
219
|
+
loadOptions: {
|
|
220
|
+
async getAccounts() {
|
|
221
|
+
return await (0, http_1.loadAccountOptions)(this);
|
|
222
|
+
},
|
|
223
|
+
},
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
async execute() {
|
|
227
|
+
const items = this.getInputData();
|
|
228
|
+
const returnData = [];
|
|
229
|
+
const resolveAccountId = (i) => {
|
|
230
|
+
const v = this.getNodeParameter('accountId', i);
|
|
231
|
+
return typeof v === 'string' ? v : v?.value;
|
|
232
|
+
};
|
|
233
|
+
for (let i = 0; i < items.length; i++) {
|
|
234
|
+
const operation = this.getNodeParameter('operation', i);
|
|
235
|
+
const accountId = resolveAccountId(i);
|
|
236
|
+
if (operation === 'list') {
|
|
237
|
+
const returnAll = this.getNodeParameter('returnAll', i);
|
|
238
|
+
const limit = this.getNodeParameter('limit', i) || 50;
|
|
239
|
+
const res = await (0, http_1.confirmxApiRequest)(this, {
|
|
240
|
+
method: 'GET',
|
|
241
|
+
endpoint: '/templates',
|
|
242
|
+
qs: { accountId },
|
|
243
|
+
});
|
|
244
|
+
const sliced = returnAll ? res.templates || [] : (res.templates || []).slice(0, limit);
|
|
245
|
+
returnData.push(...sliced.map((t) => ({ json: t })));
|
|
246
|
+
}
|
|
247
|
+
else if (operation === 'get') {
|
|
248
|
+
const name = this.getNodeParameter('name', i);
|
|
249
|
+
const language = this.getNodeParameter('language', i);
|
|
250
|
+
const res = await (0, http_1.confirmxApiRequest)(this, {
|
|
251
|
+
method: 'GET',
|
|
252
|
+
endpoint: `/templates/${accountId}/${encodeURIComponent(name)}`,
|
|
253
|
+
qs: { language },
|
|
254
|
+
});
|
|
255
|
+
returnData.push({ json: res.template });
|
|
256
|
+
}
|
|
257
|
+
else if (operation === 'create') {
|
|
258
|
+
const body = {
|
|
259
|
+
accountId,
|
|
260
|
+
name: this.getNodeParameter('createName', i),
|
|
261
|
+
language: this.getNodeParameter('createLanguage', i),
|
|
262
|
+
category: this.getNodeParameter('createCategory', i),
|
|
263
|
+
headerType: this.getNodeParameter('createHeaderType', i),
|
|
264
|
+
};
|
|
265
|
+
const headerText = this.getNodeParameter('createHeaderText', i, '');
|
|
266
|
+
const headerSamples = this.getNodeParameter('createHeaderSamples', i, '');
|
|
267
|
+
const bodyText = this.getNodeParameter('createBodyText', i);
|
|
268
|
+
const bodySamples = this.getNodeParameter('createBodySamples', i, '');
|
|
269
|
+
const footerText = this.getNodeParameter('createFooterText', i, '');
|
|
270
|
+
const buttonsRaw = this.getNodeParameter('createButtons', i, '[]');
|
|
271
|
+
if (headerText)
|
|
272
|
+
body.headerText = headerText;
|
|
273
|
+
if (headerSamples)
|
|
274
|
+
body.headerSamples = headerSamples.split(',').map((s) => s.trim()).filter(Boolean);
|
|
275
|
+
body.bodyText = bodyText;
|
|
276
|
+
if (bodySamples)
|
|
277
|
+
body.bodySamples = bodySamples.split(',').map((s) => s.trim()).filter(Boolean);
|
|
278
|
+
if (footerText)
|
|
279
|
+
body.footerText = footerText;
|
|
280
|
+
try {
|
|
281
|
+
const parsed = JSON.parse(buttonsRaw || '[]');
|
|
282
|
+
if (Array.isArray(parsed) && parsed.length)
|
|
283
|
+
body.buttons = parsed;
|
|
284
|
+
}
|
|
285
|
+
catch {
|
|
286
|
+
throw new Error('Buttons must be valid JSON array');
|
|
287
|
+
}
|
|
288
|
+
const res = await (0, http_1.confirmxApiRequest)(this, {
|
|
289
|
+
method: 'POST',
|
|
290
|
+
endpoint: '/templates',
|
|
291
|
+
body,
|
|
292
|
+
});
|
|
293
|
+
returnData.push({ json: res });
|
|
294
|
+
}
|
|
295
|
+
else if (operation === 'delete') {
|
|
296
|
+
const name = this.getNodeParameter('name', i);
|
|
297
|
+
const language = this.getNodeParameter('language', i);
|
|
298
|
+
const res = await (0, http_1.confirmxApiRequest)(this, {
|
|
299
|
+
method: 'DELETE',
|
|
300
|
+
endpoint: `/templates/${accountId}/${encodeURIComponent(name)}`,
|
|
301
|
+
qs: { language },
|
|
302
|
+
});
|
|
303
|
+
returnData.push({ json: { success: true, accountId, name, language, ...res } });
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
return [returnData];
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
exports.ConfirmXTemplate = ConfirmXTemplate;
|
|
310
|
+
//# sourceMappingURL=ConfirmXTemplate.node.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ConfirmXTemplate.node.js","sourceRoot":"","sources":["ConfirmXTemplate.node.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
import type { INodeType, INodeTypeDescription } from 'n8n-workflow'
|
|
2
|
+
import { confirmxApiRequest, loadAccountOptions } from '../../transports/http'
|
|
3
|
+
|
|
4
|
+
export class ConfirmXTemplate implements INodeType {
|
|
5
|
+
description: INodeTypeDescription = {
|
|
6
|
+
displayName: 'ConfirmX Template',
|
|
7
|
+
name: 'confirmXTemplate',
|
|
8
|
+
icon: 'file:confirmx.svg',
|
|
9
|
+
group: ['transform'],
|
|
10
|
+
version: 1,
|
|
11
|
+
subtitle: '={{$parameter["operation"]}}',
|
|
12
|
+
description:
|
|
13
|
+
'Manage Meta WhatsApp message templates — list, get, create, delete. Templates must be approved by Meta before use.',
|
|
14
|
+
defaults: { name: 'ConfirmX Template' },
|
|
15
|
+
inputs: ['main'],
|
|
16
|
+
outputs: ['main'],
|
|
17
|
+
credentials: [{ name: 'confirmXApi', required: true }],
|
|
18
|
+
properties: [
|
|
19
|
+
{
|
|
20
|
+
displayName: 'Operation',
|
|
21
|
+
name: 'operation',
|
|
22
|
+
type: 'options',
|
|
23
|
+
noDataExpression: true,
|
|
24
|
+
options: [
|
|
25
|
+
{
|
|
26
|
+
name: 'List',
|
|
27
|
+
value: 'list',
|
|
28
|
+
action: 'List templates',
|
|
29
|
+
description:
|
|
30
|
+
'List all WhatsApp message templates for an account. Returns every status — APPROVED, PENDING, REJECTED — with full `components[]`. Requires `accountId`. Use when you need to discover which templates exist before sending or auditing.',
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
name: 'Get',
|
|
34
|
+
value: 'get',
|
|
35
|
+
action: 'Get template',
|
|
36
|
+
description:
|
|
37
|
+
'Fetch a single template by name and language. Returns the live `components[]` and current Meta approval status. Requires `accountId`, `name`, and `language`. Use after a `template.status` webhook to inspect the latest version.',
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
name: 'Create',
|
|
41
|
+
value: 'create',
|
|
42
|
+
action: 'Create template',
|
|
43
|
+
description:
|
|
44
|
+
'Submit a new template for Meta approval. Returns the new template in PENDING status.',
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
name: 'Delete',
|
|
48
|
+
value: 'delete',
|
|
49
|
+
action: 'Delete template',
|
|
50
|
+
description: 'Permanently delete a template.',
|
|
51
|
+
},
|
|
52
|
+
],
|
|
53
|
+
default: 'list',
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
displayName: 'Account',
|
|
57
|
+
name: 'accountId',
|
|
58
|
+
type: 'resourceLocator',
|
|
59
|
+
default: { mode: 'list', value: '' },
|
|
60
|
+
required: true,
|
|
61
|
+
displayOptions: {
|
|
62
|
+
show: { operation: ['list', 'get', 'create', 'delete'] },
|
|
63
|
+
},
|
|
64
|
+
modes: [
|
|
65
|
+
{
|
|
66
|
+
displayName: 'From List',
|
|
67
|
+
name: 'list',
|
|
68
|
+
type: 'list',
|
|
69
|
+
placeholder: 'Select an account…',
|
|
70
|
+
typeOptions: { searchable: true },
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
displayName: 'By ID',
|
|
74
|
+
name: 'id',
|
|
75
|
+
type: 'string',
|
|
76
|
+
placeholder: 'acc_…',
|
|
77
|
+
},
|
|
78
|
+
],
|
|
79
|
+
typeOptions: {
|
|
80
|
+
loadOptionsMethod: 'getAccounts',
|
|
81
|
+
},
|
|
82
|
+
description: 'WhatsApp account to act on',
|
|
83
|
+
},
|
|
84
|
+
// --- Get / Delete ---
|
|
85
|
+
{
|
|
86
|
+
displayName: 'Name',
|
|
87
|
+
name: 'name',
|
|
88
|
+
type: 'string',
|
|
89
|
+
default: '',
|
|
90
|
+
required: true,
|
|
91
|
+
displayOptions: { show: { operation: ['get', 'delete'] } },
|
|
92
|
+
description: 'Template name (lowercase, snake_case)',
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
displayName: 'Language',
|
|
96
|
+
name: 'language',
|
|
97
|
+
type: 'string',
|
|
98
|
+
default: 'en',
|
|
99
|
+
required: true,
|
|
100
|
+
displayOptions: { show: { operation: ['get', 'delete'] } },
|
|
101
|
+
description: 'Template language code (e.g. en, ar)',
|
|
102
|
+
},
|
|
103
|
+
// --- List ---
|
|
104
|
+
{
|
|
105
|
+
displayName: 'Return All',
|
|
106
|
+
name: 'returnAll',
|
|
107
|
+
type: 'boolean',
|
|
108
|
+
default: false,
|
|
109
|
+
displayOptions: { show: { operation: ['list'] } },
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
displayName: 'Limit',
|
|
113
|
+
name: 'limit',
|
|
114
|
+
type: 'number',
|
|
115
|
+
default: 50,
|
|
116
|
+
typeOptions: { minValue: 1, maxValue: 500 },
|
|
117
|
+
displayOptions: { show: { operation: ['list'], returnAll: [false] } },
|
|
118
|
+
},
|
|
119
|
+
// --- Create ---
|
|
120
|
+
{
|
|
121
|
+
displayName: 'Template Name',
|
|
122
|
+
name: 'createName',
|
|
123
|
+
type: 'string',
|
|
124
|
+
default: '',
|
|
125
|
+
required: true,
|
|
126
|
+
displayOptions: { show: { operation: ['create'] } },
|
|
127
|
+
description: 'Lowercase, snake_case, must match /^[a-z][a-z0-9_]*$/',
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
displayName: 'Language',
|
|
131
|
+
name: 'createLanguage',
|
|
132
|
+
type: 'string',
|
|
133
|
+
default: 'en',
|
|
134
|
+
required: true,
|
|
135
|
+
displayOptions: { show: { operation: ['create'] } },
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
displayName: 'Category',
|
|
139
|
+
name: 'createCategory',
|
|
140
|
+
type: 'options',
|
|
141
|
+
default: 'UTILITY',
|
|
142
|
+
required: true,
|
|
143
|
+
options: [
|
|
144
|
+
{ name: 'Utility', value: 'UTILITY' },
|
|
145
|
+
{ name: 'Marketing', value: 'MARKETING' },
|
|
146
|
+
{ name: 'Authentication', value: 'AUTHENTICATION' },
|
|
147
|
+
],
|
|
148
|
+
displayOptions: { show: { operation: ['create'] } },
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
displayName: 'Header Type',
|
|
152
|
+
name: 'createHeaderType',
|
|
153
|
+
type: 'options',
|
|
154
|
+
default: 'NONE',
|
|
155
|
+
options: [
|
|
156
|
+
{ name: 'None', value: 'NONE' },
|
|
157
|
+
{ name: 'Text', value: 'TEXT' },
|
|
158
|
+
{ name: 'Image', value: 'IMAGE' },
|
|
159
|
+
{ name: 'Video', value: 'VIDEO' },
|
|
160
|
+
{ name: 'Document', value: 'DOCUMENT' },
|
|
161
|
+
],
|
|
162
|
+
displayOptions: { show: { operation: ['create'] } },
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
displayName: 'Header Text',
|
|
166
|
+
name: 'createHeaderText',
|
|
167
|
+
type: 'string',
|
|
168
|
+
default: '',
|
|
169
|
+
displayOptions: {
|
|
170
|
+
show: { operation: ['create'], createHeaderType: ['TEXT'] },
|
|
171
|
+
},
|
|
172
|
+
description: 'Required when header type = TEXT. Supports {{1}}, {{2}}, … placeholders.',
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
displayName: 'Header Samples',
|
|
176
|
+
name: 'createHeaderSamples',
|
|
177
|
+
type: 'string',
|
|
178
|
+
default: '',
|
|
179
|
+
displayOptions: {
|
|
180
|
+
show: { operation: ['create'], createHeaderType: ['TEXT'] },
|
|
181
|
+
},
|
|
182
|
+
description: 'Comma-separated sample values, e.g. "Acme Inc,ConfirmX"',
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
displayName: 'Body Text',
|
|
186
|
+
name: 'createBodyText',
|
|
187
|
+
type: 'string',
|
|
188
|
+
typeOptions: { rows: 4 },
|
|
189
|
+
default: '',
|
|
190
|
+
required: true,
|
|
191
|
+
displayOptions: { show: { operation: ['create'] } },
|
|
192
|
+
description: 'Body text with {{1}}, {{2}}, … placeholders',
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
displayName: 'Body Samples',
|
|
196
|
+
name: 'createBodySamples',
|
|
197
|
+
type: 'string',
|
|
198
|
+
default: '',
|
|
199
|
+
displayOptions: { show: { operation: ['create'] } },
|
|
200
|
+
description: 'Comma-separated sample values',
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
displayName: 'Footer Text',
|
|
204
|
+
name: 'createFooterText',
|
|
205
|
+
type: 'string',
|
|
206
|
+
default: '',
|
|
207
|
+
displayOptions: { show: { operation: ['create'] } },
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
displayName: 'Buttons (JSON)',
|
|
211
|
+
name: 'createButtons',
|
|
212
|
+
type: 'json',
|
|
213
|
+
default: '[]',
|
|
214
|
+
displayOptions: { show: { operation: ['create'] } },
|
|
215
|
+
description:
|
|
216
|
+
'JSON array of buttons, each `{type:"QUICK_REPLY"|"URL"|"PHONE_NUMBER", text, url?, phone_number?}`. Example: `[{"type":"URL","text":"Track","url":"https://example.com/track/{{1}}"}]`.',
|
|
217
|
+
},
|
|
218
|
+
],
|
|
219
|
+
usableAsTool: true,
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
methods = {
|
|
223
|
+
loadOptions: {
|
|
224
|
+
async getAccounts(this: any) {
|
|
225
|
+
return await loadAccountOptions(this)
|
|
226
|
+
},
|
|
227
|
+
},
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
async execute(this: any) {
|
|
231
|
+
const items = this.getInputData()
|
|
232
|
+
const returnData: any[] = []
|
|
233
|
+
const resolveAccountId = (i: number) => {
|
|
234
|
+
const v = this.getNodeParameter('accountId', i) as any
|
|
235
|
+
return typeof v === 'string' ? v : v?.value
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
for (let i = 0; i < items.length; i++) {
|
|
239
|
+
const operation = this.getNodeParameter('operation', i) as string
|
|
240
|
+
const accountId = resolveAccountId(i)
|
|
241
|
+
|
|
242
|
+
if (operation === 'list') {
|
|
243
|
+
const returnAll = this.getNodeParameter('returnAll', i) as boolean
|
|
244
|
+
const limit = (this.getNodeParameter('limit', i) as number) || 50
|
|
245
|
+
const res = await confirmxApiRequest<{ templates: any[] }>(this, {
|
|
246
|
+
method: 'GET',
|
|
247
|
+
endpoint: '/templates',
|
|
248
|
+
qs: { accountId },
|
|
249
|
+
})
|
|
250
|
+
const sliced = returnAll ? res.templates || [] : (res.templates || []).slice(0, limit)
|
|
251
|
+
returnData.push(...sliced.map((t) => ({ json: t })))
|
|
252
|
+
} else if (operation === 'get') {
|
|
253
|
+
const name = this.getNodeParameter('name', i) as string
|
|
254
|
+
const language = this.getNodeParameter('language', i) as string
|
|
255
|
+
const res = await confirmxApiRequest<{ template: any }>(this, {
|
|
256
|
+
method: 'GET',
|
|
257
|
+
endpoint: `/templates/${accountId}/${encodeURIComponent(name)}`,
|
|
258
|
+
qs: { language },
|
|
259
|
+
})
|
|
260
|
+
returnData.push({ json: res.template })
|
|
261
|
+
} else if (operation === 'create') {
|
|
262
|
+
const body: Record<string, any> = {
|
|
263
|
+
accountId,
|
|
264
|
+
name: this.getNodeParameter('createName', i) as string,
|
|
265
|
+
language: this.getNodeParameter('createLanguage', i) as string,
|
|
266
|
+
category: this.getNodeParameter('createCategory', i) as string,
|
|
267
|
+
headerType: this.getNodeParameter('createHeaderType', i) as string,
|
|
268
|
+
}
|
|
269
|
+
const headerText = this.getNodeParameter('createHeaderText', i, '') as string
|
|
270
|
+
const headerSamples = this.getNodeParameter('createHeaderSamples', i, '') as string
|
|
271
|
+
const bodyText = this.getNodeParameter('createBodyText', i) as string
|
|
272
|
+
const bodySamples = this.getNodeParameter('createBodySamples', i, '') as string
|
|
273
|
+
const footerText = this.getNodeParameter('createFooterText', i, '') as string
|
|
274
|
+
const buttonsRaw = this.getNodeParameter('createButtons', i, '[]') as string
|
|
275
|
+
|
|
276
|
+
if (headerText) body.headerText = headerText
|
|
277
|
+
if (headerSamples)
|
|
278
|
+
body.headerSamples = headerSamples.split(',').map((s) => s.trim()).filter(Boolean)
|
|
279
|
+
body.bodyText = bodyText
|
|
280
|
+
if (bodySamples)
|
|
281
|
+
body.bodySamples = bodySamples.split(',').map((s) => s.trim()).filter(Boolean)
|
|
282
|
+
if (footerText) body.footerText = footerText
|
|
283
|
+
try {
|
|
284
|
+
const parsed = JSON.parse(buttonsRaw || '[]')
|
|
285
|
+
if (Array.isArray(parsed) && parsed.length) body.buttons = parsed
|
|
286
|
+
} catch {
|
|
287
|
+
throw new Error('Buttons must be valid JSON array')
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
const res = await confirmxApiRequest<any>(this, {
|
|
291
|
+
method: 'POST',
|
|
292
|
+
endpoint: '/templates',
|
|
293
|
+
body,
|
|
294
|
+
})
|
|
295
|
+
returnData.push({ json: res })
|
|
296
|
+
} else if (operation === 'delete') {
|
|
297
|
+
const name = this.getNodeParameter('name', i) as string
|
|
298
|
+
const language = this.getNodeParameter('language', i) as string
|
|
299
|
+
const res = await confirmxApiRequest<any>(this, {
|
|
300
|
+
method: 'DELETE',
|
|
301
|
+
endpoint: `/templates/${accountId}/${encodeURIComponent(name)}`,
|
|
302
|
+
qs: { language },
|
|
303
|
+
})
|
|
304
|
+
returnData.push({ json: { success: true, accountId, name, language, ...res } })
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
return [returnData]
|
|
309
|
+
}
|
|
310
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ConfirmX Trigger — starts a flow when ConfirmX emits a webhook event.
|
|
3
|
+
*
|
|
4
|
+
* Self-registration lifecycle:
|
|
5
|
+
* 1. `trigger()` — n8n calls this when the trigger is added/edited or
|
|
6
|
+
* the workflow is saved/activated. We POST /api/v1/webhooks with
|
|
7
|
+
* the n8n-generated URL + the selected events, then persist the
|
|
8
|
+
* returned `secret` in workflow staticData.
|
|
9
|
+
* 2. `webhook()` — n8n calls this for each incoming POST from ConfirmX.
|
|
10
|
+
* We verify the HMAC signature, reject stale timestamps (300s window),
|
|
11
|
+
* and emit the envelope's `data` field as the n8n item.
|
|
12
|
+
* 3. `delete()` / `deactivate()` — best-effort DELETE /api/v1/webhooks/:id.
|
|
13
|
+
*
|
|
14
|
+
* Critical invariant: the `secret` MUST persist client-side because
|
|
15
|
+
* `GET /api/v1/webhooks/:id` does NOT return it. If staticData is wiped
|
|
16
|
+
* (e.g. n8n SQLite volume loss), the trigger throws a clear error
|
|
17
|
+
* and the user must re-add the node to re-register.
|
|
18
|
+
*/
|
|
19
|
+
import type { ITriggerFunctions, ITriggerResponse, IWebhookFunctions, INodeType, INodeTypeDescription } from 'n8n-workflow';
|
|
20
|
+
export declare class ConfirmXTrigger implements INodeType {
|
|
21
|
+
description: INodeTypeDescription;
|
|
22
|
+
trigger(this: ITriggerFunctions): Promise<ITriggerResponse>;
|
|
23
|
+
webhook(this: IWebhookFunctions): Promise<{
|
|
24
|
+
workflowData: {
|
|
25
|
+
json: any;
|
|
26
|
+
}[][];
|
|
27
|
+
}>;
|
|
28
|
+
delete(this: ITriggerFunctions): Promise<void>;
|
|
29
|
+
}
|