n8n-nodes-kirimi 1.0.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/README.md ADDED
@@ -0,0 +1,82 @@
1
+ # n8n-nodes-kirimi
2
+
3
+ This is an n8n community node for integrating with the Kirimi WhatsApp Unofficial API.
4
+
5
+ ## Features
6
+
7
+ The Kirimi node provides comprehensive integration with Kirimi's WhatsApp Unofficial API, including:
8
+
9
+ ### OTP Management
10
+ - Generate OTP and send via WhatsApp
11
+ - Validate OTP codes
12
+ - Customizable OTP length, type, and messages
13
+
14
+ ### Message Sending
15
+ - Send individual WhatsApp messages
16
+ - Send messages in fast mode (no typing effect)
17
+ - Broadcast messages to multiple recipients
18
+ - Support for text and media messages
19
+
20
+ ### Device Management
21
+ - Create new WhatsApp devices
22
+ - Connect devices via QR code
23
+ - Check device status
24
+ - List all devices
25
+ - Renew device subscriptions
26
+
27
+ ### Contact Management
28
+ - Save individual contacts
29
+ - Bulk save multiple contacts
30
+
31
+ ### Package & Billing
32
+ - List available packages
33
+ - Create deposits for top-up
34
+ - Check deposit status
35
+
36
+ ### User Information
37
+ - Get user account information
38
+
39
+ ### Security & Monitoring
40
+ - Check OTP security status
41
+ - Get merchant reputation
42
+ - View customer OTP statistics
43
+
44
+ ### Utilities
45
+ - Test phone number normalization
46
+
47
+ ## Installation
48
+
49
+ 1. Install in n8n community nodes:
50
+ ```
51
+ npm install n8n-nodes-kirimi
52
+ ```
53
+
54
+ 2. Restart n8n to load the node
55
+
56
+ ## Configuration
57
+
58
+ 1. Create Kirimi API credentials in n8n:
59
+ - User Code: Your Kirimi API user code
60
+ - Secret: Your Kirimi API secret key
61
+ - Base URL: https://api.kirimi.id/v1 (default)
62
+
63
+ 2. Get your credentials from [Kirimi Documentation](https://kirimi.id/docs)
64
+
65
+ ## Usage
66
+
67
+ 1. Add the Kirimi node to your workflow
68
+ 2. Select the appropriate resource and operation
69
+ 3. Configure the required parameters
70
+ 4. Execute the workflow
71
+
72
+ ## API Documentation
73
+
74
+ For detailed API documentation, visit: https://kirimi.id/docs
75
+
76
+ ## Support
77
+
78
+ For issues and feature requests, please visit: https://github.com/kiriminow/n8n-kirimi-nodes/issues
79
+
80
+ ## License
81
+
82
+ MIT# n8n-nodes-kirimi
@@ -0,0 +1,9 @@
1
+ import { IAuthenticateGeneric, ICredentialTestRequest, ICredentialType, INodeProperties } from 'n8n-workflow';
2
+ export declare class KirimiApi implements ICredentialType {
3
+ name: string;
4
+ displayName: string;
5
+ documentationUrl: string;
6
+ properties: INodeProperties[];
7
+ authenticate: IAuthenticateGeneric;
8
+ test: ICredentialTestRequest;
9
+ }
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.KirimiApi = void 0;
4
+ class KirimiApi {
5
+ constructor() {
6
+ this.name = 'kirimiApi';
7
+ this.displayName = 'Kirimi API';
8
+ this.documentationUrl = 'https://kirimi.id/docs';
9
+ this.properties = [
10
+ {
11
+ displayName: 'User Code',
12
+ name: 'userCode',
13
+ type: 'string',
14
+ required: true,
15
+ default: '',
16
+ description: 'Your Kirimi API user code',
17
+ },
18
+ {
19
+ displayName: 'Secret',
20
+ name: 'secret',
21
+ type: 'string',
22
+ required: true,
23
+ typeOptions: { password: true },
24
+ default: '',
25
+ description: 'Your Kirimi API secret key',
26
+ },
27
+ {
28
+ displayName: 'Base URL',
29
+ name: 'baseUrl',
30
+ type: 'string',
31
+ required: true,
32
+ default: 'https://api.kirimi.id/v1',
33
+ description: 'The base URL for the Kirimi API',
34
+ },
35
+ ];
36
+ this.authenticate = {
37
+ type: 'generic',
38
+ properties: {
39
+ body: {
40
+ user_code: '={{$credentials.userCode}}',
41
+ secret: '={{$credentials.secret}}',
42
+ },
43
+ },
44
+ };
45
+ this.test = {
46
+ request: {
47
+ baseURL: '={{$credentials.baseUrl}}',
48
+ url: '/user-info',
49
+ method: 'POST',
50
+ },
51
+ };
52
+ }
53
+ }
54
+ exports.KirimiApi = KirimiApi;
@@ -0,0 +1,8 @@
1
+ <svg width="60" height="60" viewBox="0 0 60 60" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <rect width="60" height="60" rx="12" fill="#25D366"/>
3
+ <path d="M30 8C18.954 8 10 16.954 10 28c0 3.618.967 7.024 2.658 9.952L10 52l14.348-2.618C26.976 51.033 28.382 52 30 52c11.046 0 20-8.954 20-20S41.046 8 30 8z" fill="white"/>
4
+ <path d="M24 22c0-1.104.896-2 2-2h8c1.104 0 2 .896 2 2v8c0 1.104-.896 2-2 2h-8c-1.104 0-2-.896-2-2v-8z" fill="#25D366"/>
5
+ <path d="M20 28c0-1.104.896-2 2-2h4v4h-4c-1.104 0-2-.896-2-2z" fill="#25D366"/>
6
+ <path d="M34 30h4c1.104 0 2 .896 2 2s-.896 2-2 2h-4v-4z" fill="#25D366"/>
7
+ <path d="M26 36h8c1.104 0 2 .896 2 2s-.896 2-2 2h-8c-1.104 0-2-.896-2-2s.896-2 2-2z" fill="#25D366"/>
8
+ </svg>
@@ -0,0 +1,2 @@
1
+ import { IDataObject, IExecuteFunctions, IHttpRequestMethods, ILoadOptionsFunctions } from 'n8n-workflow';
2
+ export declare function kirimiApiRequest(this: IExecuteFunctions | ILoadOptionsFunctions, method: IHttpRequestMethods, endpoint: string, body?: any, query?: IDataObject): Promise<any>;
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.kirimiApiRequest = void 0;
4
+ const n8n_workflow_1 = require("n8n-workflow");
5
+ async function kirimiApiRequest(method, endpoint, body = {}, query = {}) {
6
+ const credentials = await this.getCredentials('kirimiApi');
7
+ const options = {
8
+ method,
9
+ body,
10
+ qs: query,
11
+ url: `${credentials.baseUrl}${endpoint}`,
12
+ json: true,
13
+ };
14
+ if (Object.keys(body).length === 0) {
15
+ delete options.body;
16
+ }
17
+ try {
18
+ return await this.helpers.httpRequest.call(this, options);
19
+ }
20
+ catch (error) {
21
+ throw new n8n_workflow_1.NodeApiError(this.getNode(), error);
22
+ }
23
+ }
24
+ exports.kirimiApiRequest = kirimiApiRequest;
@@ -0,0 +1,5 @@
1
+ import { IExecuteFunctions, INodeExecutionData, INodeType, INodeTypeDescription } from 'n8n-workflow';
2
+ export declare class Kirimi implements INodeType {
3
+ description: INodeTypeDescription;
4
+ execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
5
+ }
@@ -0,0 +1,998 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Kirimi = void 0;
4
+ const n8n_workflow_1 = require("n8n-workflow");
5
+ const GenericFunctions_1 = require("./GenericFunctions");
6
+ class Kirimi {
7
+ constructor() {
8
+ this.description = {
9
+ displayName: 'Kirimi',
10
+ name: 'kirimi',
11
+ icon: 'file:kirimi.svg',
12
+ group: ['communication'],
13
+ version: 1,
14
+ subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
15
+ description: 'Interact with Kirimi WhatsApp Unofficial API',
16
+ defaults: {
17
+ name: 'Kirimi',
18
+ },
19
+ inputs: ['main'],
20
+ outputs: ['main'],
21
+ credentials: [
22
+ {
23
+ name: 'kirimiApi',
24
+ required: true,
25
+ },
26
+ ],
27
+ properties: [
28
+ {
29
+ displayName: 'Resource',
30
+ name: 'resource',
31
+ type: 'options',
32
+ noDataExpression: true,
33
+ options: [
34
+ {
35
+ name: 'Contact',
36
+ value: 'contact',
37
+ description: 'Contact management operations',
38
+ },
39
+ {
40
+ name: 'Device',
41
+ value: 'device',
42
+ description: 'Device management operations',
43
+ },
44
+ {
45
+ name: 'Message',
46
+ value: 'message',
47
+ description: 'Message sending operations',
48
+ },
49
+ {
50
+ name: 'OTP',
51
+ value: 'otp',
52
+ description: 'OTP management operations',
53
+ },
54
+ {
55
+ name: 'Package',
56
+ value: 'package',
57
+ description: 'Package and billing operations',
58
+ },
59
+ {
60
+ name: 'Security',
61
+ value: 'security',
62
+ description: 'Security and monitoring operations',
63
+ },
64
+ {
65
+ name: 'User',
66
+ value: 'user',
67
+ description: 'User information operations',
68
+ },
69
+ {
70
+ name: 'Utility',
71
+ value: 'utility',
72
+ description: 'Testing and utility operations',
73
+ },
74
+ ],
75
+ default: 'message',
76
+ required: true,
77
+ },
78
+ // OTP Operations
79
+ {
80
+ displayName: 'Operation',
81
+ name: 'operation',
82
+ type: 'options',
83
+ noDataExpression: true,
84
+ displayOptions: {
85
+ show: {
86
+ resource: ['otp'],
87
+ },
88
+ },
89
+ options: [
90
+ {
91
+ name: 'Generate OTP',
92
+ value: 'generateOtp',
93
+ description: 'Generate and send OTP via WhatsApp',
94
+ action: 'Generate an OTP',
95
+ },
96
+ {
97
+ name: 'Validate OTP',
98
+ value: 'validateOtp',
99
+ description: 'Validate OTP code',
100
+ action: 'Validate an OTP',
101
+ },
102
+ ],
103
+ default: 'generateOtp',
104
+ required: true,
105
+ },
106
+ // Message Operations
107
+ {
108
+ displayName: 'Operation',
109
+ name: 'operation',
110
+ type: 'options',
111
+ noDataExpression: true,
112
+ displayOptions: {
113
+ show: {
114
+ resource: ['message'],
115
+ },
116
+ },
117
+ options: [
118
+ {
119
+ name: 'Send Message',
120
+ value: 'sendMessage',
121
+ description: 'Send a WhatsApp message',
122
+ action: 'Send a message',
123
+ },
124
+ {
125
+ name: 'Send Message Fast',
126
+ value: 'sendMessageFast',
127
+ description: 'Send a WhatsApp message (fast mode)',
128
+ action: 'Send a message fast',
129
+ },
130
+ {
131
+ name: 'Broadcast Message',
132
+ value: 'broadcastMessage',
133
+ description: 'Send message to multiple recipients',
134
+ action: 'Broadcast a message',
135
+ },
136
+ ],
137
+ default: 'sendMessage',
138
+ required: true,
139
+ },
140
+ // Device Operations
141
+ {
142
+ displayName: 'Operation',
143
+ name: 'operation',
144
+ type: 'options',
145
+ noDataExpression: true,
146
+ displayOptions: {
147
+ show: {
148
+ resource: ['device'],
149
+ },
150
+ },
151
+ options: [
152
+ {
153
+ name: 'Connect Device',
154
+ value: 'connectDevice',
155
+ description: 'Connect WhatsApp device',
156
+ action: 'Connect a device',
157
+ },
158
+ {
159
+ name: 'Create Device',
160
+ value: 'createDevice',
161
+ description: 'Create a new WhatsApp device',
162
+ action: 'Create a device',
163
+ },
164
+ {
165
+ name: 'Device Status',
166
+ value: 'deviceStatus',
167
+ description: 'Check device status',
168
+ action: 'Get device status',
169
+ },
170
+ {
171
+ name: 'List Devices',
172
+ value: 'listDevices',
173
+ description: 'List all devices',
174
+ action: 'List devices',
175
+ },
176
+ {
177
+ name: 'Renew Device',
178
+ value: 'renewDevice',
179
+ description: 'Renew device subscription',
180
+ action: 'Renew a device',
181
+ },
182
+ ],
183
+ default: 'deviceStatus',
184
+ required: true,
185
+ },
186
+ // Contact Operations
187
+ {
188
+ displayName: 'Operation',
189
+ name: 'operation',
190
+ type: 'options',
191
+ noDataExpression: true,
192
+ displayOptions: {
193
+ show: {
194
+ resource: ['contact'],
195
+ },
196
+ },
197
+ options: [
198
+ {
199
+ name: 'Save Contact',
200
+ value: 'saveContact',
201
+ description: 'Save a single contact',
202
+ action: 'Save a contact',
203
+ },
204
+ {
205
+ name: 'Save Contacts Bulk',
206
+ value: 'saveContactsBulk',
207
+ description: 'Save multiple contacts',
208
+ action: 'Save contacts in bulk',
209
+ },
210
+ ],
211
+ default: 'saveContact',
212
+ required: true,
213
+ },
214
+ // Package Operations
215
+ {
216
+ displayName: 'Operation',
217
+ name: 'operation',
218
+ type: 'options',
219
+ noDataExpression: true,
220
+ displayOptions: {
221
+ show: {
222
+ resource: ['package'],
223
+ },
224
+ },
225
+ options: [
226
+ {
227
+ name: 'List Packages',
228
+ value: 'listPackages',
229
+ description: 'Get available packages',
230
+ action: 'List packages',
231
+ },
232
+ {
233
+ name: 'Create Deposit',
234
+ value: 'createDeposit',
235
+ description: 'Create a deposit for top-up',
236
+ action: 'Create a deposit',
237
+ },
238
+ {
239
+ name: 'Deposit Status',
240
+ value: 'depositStatus',
241
+ description: 'Check deposit status',
242
+ action: 'Get deposit status',
243
+ },
244
+ ],
245
+ default: 'listPackages',
246
+ required: true,
247
+ },
248
+ // User Operations
249
+ {
250
+ displayName: 'Operation',
251
+ name: 'operation',
252
+ type: 'options',
253
+ noDataExpression: true,
254
+ displayOptions: {
255
+ show: {
256
+ resource: ['user'],
257
+ },
258
+ },
259
+ options: [
260
+ {
261
+ name: 'User Info',
262
+ value: 'userInfo',
263
+ description: 'Get user information',
264
+ action: 'Get user info',
265
+ },
266
+ ],
267
+ default: 'userInfo',
268
+ required: true,
269
+ },
270
+ // Security Operations
271
+ {
272
+ displayName: 'Operation',
273
+ name: 'operation',
274
+ type: 'options',
275
+ noDataExpression: true,
276
+ displayOptions: {
277
+ show: {
278
+ resource: ['security'],
279
+ },
280
+ },
281
+ options: [
282
+ {
283
+ name: 'OTP Security Status',
284
+ value: 'otpSecurityStatus',
285
+ description: 'Check OTP security status',
286
+ action: 'Get OTP security status',
287
+ },
288
+ {
289
+ name: 'Merchant Reputation',
290
+ value: 'merchantReputation',
291
+ description: 'Check merchant reputation',
292
+ action: 'Get merchant reputation',
293
+ },
294
+ {
295
+ name: 'Customer OTP Stats',
296
+ value: 'customerOtpStats',
297
+ description: 'Get customer OTP statistics',
298
+ action: 'Get customer OTP stats',
299
+ },
300
+ ],
301
+ default: 'otpSecurityStatus',
302
+ required: true,
303
+ },
304
+ // Utility Operations
305
+ {
306
+ displayName: 'Operation',
307
+ name: 'operation',
308
+ type: 'options',
309
+ noDataExpression: true,
310
+ displayOptions: {
311
+ show: {
312
+ resource: ['utility'],
313
+ },
314
+ },
315
+ options: [
316
+ {
317
+ name: 'Test Phone Normalization',
318
+ value: 'testPhoneNormalization',
319
+ description: 'Test phone number normalization',
320
+ action: 'Test phone normalization',
321
+ },
322
+ ],
323
+ default: 'testPhoneNormalization',
324
+ required: true,
325
+ },
326
+ // Device ID field (required for most operations)
327
+ {
328
+ displayName: 'Device ID',
329
+ name: 'deviceId',
330
+ type: 'string',
331
+ required: true,
332
+ displayOptions: {
333
+ show: {
334
+ resource: ['otp', 'message', 'contact'],
335
+ },
336
+ },
337
+ default: '',
338
+ description: 'The WhatsApp device ID to use',
339
+ },
340
+ {
341
+ displayName: 'Device ID',
342
+ name: 'deviceId',
343
+ type: 'string',
344
+ required: true,
345
+ displayOptions: {
346
+ show: {
347
+ resource: ['device'],
348
+ operation: ['connectDevice', 'deviceStatus', 'renewDevice'],
349
+ },
350
+ },
351
+ default: '',
352
+ description: 'The WhatsApp device ID to use',
353
+ },
354
+ // OTP Fields
355
+ {
356
+ displayName: 'Phone Number',
357
+ name: 'phone',
358
+ type: 'string',
359
+ required: true,
360
+ displayOptions: {
361
+ show: {
362
+ resource: ['otp'],
363
+ },
364
+ },
365
+ default: '',
366
+ description: 'Phone number (format: 08xxx, 62xxx, +62xxx)',
367
+ },
368
+ {
369
+ displayName: 'OTP Code',
370
+ name: 'otp',
371
+ type: 'string',
372
+ required: true,
373
+ displayOptions: {
374
+ show: {
375
+ resource: ['otp'],
376
+ operation: ['validateOtp'],
377
+ },
378
+ },
379
+ default: '',
380
+ description: 'The OTP code to validate',
381
+ },
382
+ {
383
+ displayName: 'Enable Typing Effect',
384
+ name: 'enableTypingEffect',
385
+ type: 'boolean',
386
+ displayOptions: {
387
+ show: {
388
+ resource: ['otp'],
389
+ operation: ['generateOtp'],
390
+ },
391
+ },
392
+ default: true,
393
+ description: 'Whether to enable typing effect',
394
+ },
395
+ {
396
+ displayName: 'Typing Speed (Ms)',
397
+ name: 'typingSpeedMs',
398
+ type: 'number',
399
+ displayOptions: {
400
+ show: {
401
+ resource: ['otp'],
402
+ operation: ['generateOtp'],
403
+ enableTypingEffect: [true],
404
+ },
405
+ },
406
+ default: 50,
407
+ description: 'Typing speed in milliseconds',
408
+ },
409
+ {
410
+ displayName: 'OTP Length',
411
+ name: 'otpLength',
412
+ type: 'number',
413
+ displayOptions: {
414
+ show: {
415
+ resource: ['otp'],
416
+ operation: ['generateOtp'],
417
+ },
418
+ },
419
+ default: 8,
420
+ description: 'Length of the OTP (4-20)',
421
+ },
422
+ {
423
+ displayName: 'OTP Type',
424
+ name: 'otpType',
425
+ type: 'options',
426
+ displayOptions: {
427
+ show: {
428
+ resource: ['otp'],
429
+ operation: ['generateOtp'],
430
+ },
431
+ },
432
+ options: [
433
+ {
434
+ name: 'Numeric',
435
+ value: 'numeric',
436
+ },
437
+ {
438
+ name: 'Alphabetic',
439
+ value: 'alphabetic',
440
+ },
441
+ {
442
+ name: 'Alphanumeric',
443
+ value: 'alphanumeric',
444
+ },
445
+ ],
446
+ default: 'numeric',
447
+ description: 'Type of OTP to generate',
448
+ },
449
+ {
450
+ displayName: 'Custom OTP Text',
451
+ name: 'customOtpText',
452
+ type: 'string',
453
+ displayOptions: {
454
+ show: {
455
+ resource: ['otp'],
456
+ operation: ['generateOtp'],
457
+ },
458
+ },
459
+ default: '',
460
+ description: 'Custom OTP text (optional)',
461
+ },
462
+ {
463
+ displayName: 'Custom OTP Message',
464
+ name: 'customOtpMessage',
465
+ type: 'string',
466
+ displayOptions: {
467
+ show: {
468
+ resource: ['otp'],
469
+ operation: ['generateOtp'],
470
+ },
471
+ },
472
+ default: '',
473
+ description: 'Custom message template (must contain {otp})',
474
+ },
475
+ // Message Fields
476
+ {
477
+ displayName: 'Receiver',
478
+ name: 'receiver',
479
+ type: 'string',
480
+ required: true,
481
+ displayOptions: {
482
+ show: {
483
+ resource: ['message'],
484
+ operation: ['sendMessage', 'sendMessageFast'],
485
+ },
486
+ },
487
+ default: '',
488
+ description: 'Phone number or group ID (format: 08xxx, 62xxx, +62xxx, xxxxxxxxx@g.us)',
489
+ },
490
+ {
491
+ displayName: 'Message',
492
+ name: 'message',
493
+ type: 'string',
494
+ displayOptions: {
495
+ show: {
496
+ resource: ['message'],
497
+ operation: ['sendMessage', 'sendMessageFast'],
498
+ },
499
+ },
500
+ default: '',
501
+ description: 'Text message (required if media_url is empty)',
502
+ },
503
+ {
504
+ displayName: 'Media URL',
505
+ name: 'mediaUrl',
506
+ type: 'string',
507
+ displayOptions: {
508
+ show: {
509
+ resource: ['message'],
510
+ operation: ['sendMessage', 'sendMessageFast'],
511
+ },
512
+ },
513
+ default: '',
514
+ description: 'URL for media (image, video, document)',
515
+ },
516
+ {
517
+ displayName: 'Enable Typing Effect',
518
+ name: 'enableTypingEffect',
519
+ type: 'boolean',
520
+ displayOptions: {
521
+ show: {
522
+ resource: ['message'],
523
+ operation: ['sendMessage'],
524
+ },
525
+ },
526
+ default: true,
527
+ description: 'Whether to enable typing effect',
528
+ },
529
+ {
530
+ displayName: 'Typing Speed (Ms)',
531
+ name: 'typingSpeedMs',
532
+ type: 'number',
533
+ displayOptions: {
534
+ show: {
535
+ resource: ['message'],
536
+ operation: ['sendMessage'],
537
+ enableTypingEffect: [true],
538
+ },
539
+ },
540
+ default: 50,
541
+ description: 'Typing speed in milliseconds',
542
+ },
543
+ // Broadcast Fields
544
+ {
545
+ displayName: 'Label',
546
+ name: 'label',
547
+ type: 'string',
548
+ required: true,
549
+ displayOptions: {
550
+ show: {
551
+ resource: ['message'],
552
+ operation: ['broadcastMessage'],
553
+ },
554
+ },
555
+ default: '',
556
+ description: 'Label for the broadcast',
557
+ },
558
+ {
559
+ displayName: 'Phone Numbers',
560
+ name: 'numbers',
561
+ type: 'string',
562
+ required: true,
563
+ displayOptions: {
564
+ show: {
565
+ resource: ['message'],
566
+ operation: ['broadcastMessage'],
567
+ },
568
+ },
569
+ default: '',
570
+ description: 'Comma-separated phone numbers (max 500 for free, 2000 for premium)',
571
+ },
572
+ {
573
+ displayName: 'Broadcast Message',
574
+ name: 'message',
575
+ type: 'string',
576
+ displayOptions: {
577
+ show: {
578
+ resource: ['message'],
579
+ operation: ['broadcastMessage'],
580
+ },
581
+ },
582
+ default: '',
583
+ description: 'Text message (required if media_url is empty)',
584
+ },
585
+ {
586
+ displayName: 'Media URL',
587
+ name: 'mediaUrl',
588
+ type: 'string',
589
+ displayOptions: {
590
+ show: {
591
+ resource: ['message'],
592
+ operation: ['broadcastMessage'],
593
+ },
594
+ },
595
+ default: '',
596
+ description: 'URL for media (image, video, document)',
597
+ },
598
+ {
599
+ displayName: 'Delay (Seconds)',
600
+ name: 'delay',
601
+ type: 'number',
602
+ displayOptions: {
603
+ show: {
604
+ resource: ['message'],
605
+ operation: ['broadcastMessage'],
606
+ },
607
+ },
608
+ default: 30,
609
+ description: 'Delay between messages in seconds (minimum 30)',
610
+ },
611
+ {
612
+ displayName: 'Delay Min (Seconds)',
613
+ name: 'delayMin',
614
+ type: 'number',
615
+ displayOptions: {
616
+ show: {
617
+ resource: ['message'],
618
+ operation: ['broadcastMessage'],
619
+ },
620
+ },
621
+ default: '',
622
+ description: 'Minimum delay (optional)',
623
+ },
624
+ {
625
+ displayName: 'Delay Max (Seconds)',
626
+ name: 'delayMax',
627
+ type: 'number',
628
+ displayOptions: {
629
+ show: {
630
+ resource: ['message'],
631
+ operation: ['broadcastMessage'],
632
+ },
633
+ },
634
+ default: '',
635
+ description: 'Maximum delay (optional)',
636
+ },
637
+ {
638
+ displayName: 'Start Time',
639
+ name: 'startedAt',
640
+ type: 'dateTime',
641
+ displayOptions: {
642
+ show: {
643
+ resource: ['message'],
644
+ operation: ['broadcastMessage'],
645
+ },
646
+ },
647
+ default: '',
648
+ description: 'When to start the broadcast (optional)',
649
+ },
650
+ // Device Fields
651
+ {
652
+ displayName: 'Package ID',
653
+ name: 'packageId',
654
+ type: 'number',
655
+ required: true,
656
+ displayOptions: {
657
+ show: {
658
+ resource: ['device'],
659
+ operation: ['createDevice', 'renewDevice'],
660
+ },
661
+ },
662
+ default: 1,
663
+ description: 'Package ID for the device',
664
+ },
665
+ {
666
+ displayName: 'Voucher Code',
667
+ name: 'voucherCode',
668
+ type: 'string',
669
+ displayOptions: {
670
+ show: {
671
+ resource: ['device'],
672
+ operation: ['createDevice', 'renewDevice'],
673
+ },
674
+ },
675
+ default: '',
676
+ description: 'Voucher code (optional)',
677
+ },
678
+ // Contact Fields
679
+ {
680
+ displayName: 'Contact Name',
681
+ name: 'name',
682
+ type: 'string',
683
+ required: true,
684
+ displayOptions: {
685
+ show: {
686
+ resource: ['contact'],
687
+ operation: ['saveContact'],
688
+ },
689
+ },
690
+ default: '',
691
+ },
692
+ {
693
+ displayName: 'Phone Number',
694
+ name: 'phone',
695
+ type: 'string',
696
+ required: true,
697
+ displayOptions: {
698
+ show: {
699
+ resource: ['contact'],
700
+ operation: ['saveContact'],
701
+ },
702
+ },
703
+ default: '',
704
+ },
705
+ {
706
+ displayName: 'Email',
707
+ name: 'email',
708
+ type: 'string',
709
+ placeholder: 'name@email.com',
710
+ displayOptions: {
711
+ show: {
712
+ resource: ['contact'],
713
+ operation: ['saveContact'],
714
+ },
715
+ },
716
+ default: '',
717
+ description: 'Email address (optional)',
718
+ },
719
+ {
720
+ displayName: 'Company',
721
+ name: 'company',
722
+ type: 'string',
723
+ displayOptions: {
724
+ show: {
725
+ resource: ['contact'],
726
+ operation: ['saveContact'],
727
+ },
728
+ },
729
+ default: '',
730
+ description: 'Company name (optional)',
731
+ },
732
+ {
733
+ displayName: 'Contacts',
734
+ name: 'contacts',
735
+ type: 'string',
736
+ required: true,
737
+ displayOptions: {
738
+ show: {
739
+ resource: ['contact'],
740
+ operation: ['saveContactsBulk'],
741
+ },
742
+ },
743
+ default: '',
744
+ description: 'JSON array of contacts with name, phone, email, company fields',
745
+ },
746
+ // Package Fields
747
+ {
748
+ displayName: 'Amount',
749
+ name: 'amount',
750
+ type: 'number',
751
+ required: true,
752
+ displayOptions: {
753
+ show: {
754
+ resource: ['package'],
755
+ operation: ['createDeposit'],
756
+ },
757
+ },
758
+ default: 1,
759
+ description: 'Deposit amount',
760
+ },
761
+ {
762
+ displayName: 'Payment Method',
763
+ name: 'paymentMethod',
764
+ type: 'string',
765
+ required: true,
766
+ displayOptions: {
767
+ show: {
768
+ resource: ['package'],
769
+ operation: ['createDeposit'],
770
+ },
771
+ },
772
+ default: '',
773
+ },
774
+ {
775
+ displayName: 'Deposit ID',
776
+ name: 'depositId',
777
+ type: 'string',
778
+ required: true,
779
+ displayOptions: {
780
+ show: {
781
+ resource: ['package'],
782
+ operation: ['depositStatus'],
783
+ },
784
+ },
785
+ default: '',
786
+ description: 'Deposit ID to check status',
787
+ },
788
+ // Utility Fields
789
+ {
790
+ displayName: 'Phone Number',
791
+ name: 'phone',
792
+ type: 'string',
793
+ required: true,
794
+ displayOptions: {
795
+ show: {
796
+ resource: ['utility'],
797
+ operation: ['testPhoneNormalization'],
798
+ },
799
+ },
800
+ default: '',
801
+ description: 'Phone number to normalize',
802
+ },
803
+ ],
804
+ };
805
+ }
806
+ async execute() {
807
+ const items = this.getInputData();
808
+ const returnData = [];
809
+ const resource = this.getNodeParameter('resource', 0);
810
+ const operation = this.getNodeParameter('operation', 0);
811
+ for (let i = 0; i < items.length; i++) {
812
+ const body = {};
813
+ let endpoint = '';
814
+ let method = 'POST';
815
+ // Add authentication to all requests
816
+ const credentials = await this.getCredentials('kirimiApi');
817
+ body.user_code = credentials.userCode;
818
+ body.secret = credentials.secret;
819
+ try {
820
+ if (resource === 'otp') {
821
+ if (operation === 'generateOtp') {
822
+ endpoint = '/generate-otp';
823
+ body.device_id = this.getNodeParameter('deviceId', i);
824
+ body.phone = this.getNodeParameter('phone', i);
825
+ body.enableTypingEffect = this.getNodeParameter('enableTypingEffect', i);
826
+ body.typingSpeedMs = this.getNodeParameter('typingSpeedMs', i);
827
+ body.otpLength = this.getNodeParameter('otpLength', i);
828
+ body.otpType = this.getNodeParameter('otpType', i);
829
+ const customOtpText = this.getNodeParameter('customOtpText', i);
830
+ if (customOtpText)
831
+ body.customOtpText = customOtpText;
832
+ const customOtpMessage = this.getNodeParameter('customOtpMessage', i);
833
+ if (customOtpMessage)
834
+ body.customOtpMessage = customOtpMessage;
835
+ }
836
+ else if (operation === 'validateOtp') {
837
+ endpoint = '/validate-otp';
838
+ body.device_id = this.getNodeParameter('deviceId', i);
839
+ body.phone = this.getNodeParameter('phone', i);
840
+ body.otp = this.getNodeParameter('otp', i);
841
+ }
842
+ }
843
+ else if (resource === 'message') {
844
+ if (operation === 'sendMessage') {
845
+ endpoint = '/send-message';
846
+ body.device_id = this.getNodeParameter('deviceId', i);
847
+ body.receiver = this.getNodeParameter('receiver', i);
848
+ const message = this.getNodeParameter('message', i);
849
+ if (message)
850
+ body.message = message;
851
+ const mediaUrl = this.getNodeParameter('mediaUrl', i);
852
+ if (mediaUrl)
853
+ body.media_url = mediaUrl;
854
+ body.enableTypingEffect = this.getNodeParameter('enableTypingEffect', i);
855
+ body.typingSpeedMs = this.getNodeParameter('typingSpeedMs', i);
856
+ }
857
+ else if (operation === 'sendMessageFast') {
858
+ endpoint = '/send-message-fast';
859
+ body.device_id = this.getNodeParameter('deviceId', i);
860
+ body.receiver = this.getNodeParameter('receiver', i);
861
+ const message = this.getNodeParameter('message', i);
862
+ if (message)
863
+ body.message = message;
864
+ const mediaUrl = this.getNodeParameter('mediaUrl', i);
865
+ if (mediaUrl)
866
+ body.media_url = mediaUrl;
867
+ }
868
+ else if (operation === 'broadcastMessage') {
869
+ endpoint = '/broadcast-message';
870
+ body.device_id = this.getNodeParameter('deviceId', i);
871
+ body.label = this.getNodeParameter('label', i);
872
+ const numbersString = this.getNodeParameter('numbers', i);
873
+ body.numbers = numbersString.split(',').map((num) => num.trim());
874
+ const message = this.getNodeParameter('message', i);
875
+ if (message)
876
+ body.message = message;
877
+ const mediaUrl = this.getNodeParameter('mediaUrl', i);
878
+ if (mediaUrl)
879
+ body.media_url = mediaUrl;
880
+ body.delay = this.getNodeParameter('delay', i);
881
+ const delayMin = this.getNodeParameter('delayMin', i);
882
+ if (delayMin)
883
+ body.delayMin = delayMin;
884
+ const delayMax = this.getNodeParameter('delayMax', i);
885
+ if (delayMax)
886
+ body.delayMax = delayMax;
887
+ const startedAt = this.getNodeParameter('startedAt', i);
888
+ if (startedAt)
889
+ body.started_at = startedAt;
890
+ }
891
+ }
892
+ else if (resource === 'device') {
893
+ if (operation === 'createDevice') {
894
+ endpoint = '/create-device';
895
+ body.package_id = this.getNodeParameter('packageId', i);
896
+ const voucherCode = this.getNodeParameter('voucherCode', i);
897
+ if (voucherCode)
898
+ body.voucher_code = voucherCode;
899
+ }
900
+ else if (operation === 'connectDevice') {
901
+ endpoint = '/connect-device';
902
+ body.device_id = this.getNodeParameter('deviceId', i);
903
+ }
904
+ else if (operation === 'deviceStatus') {
905
+ endpoint = '/device-status';
906
+ body.device_id = this.getNodeParameter('deviceId', i);
907
+ }
908
+ else if (operation === 'listDevices') {
909
+ endpoint = '/list-devices';
910
+ }
911
+ else if (operation === 'renewDevice') {
912
+ endpoint = '/renew-device';
913
+ body.device_id = this.getNodeParameter('deviceId', i);
914
+ body.package_id = this.getNodeParameter('packageId', i);
915
+ const voucherCode = this.getNodeParameter('voucherCode', i);
916
+ if (voucherCode)
917
+ body.voucher_code = voucherCode;
918
+ }
919
+ }
920
+ else if (resource === 'contact') {
921
+ if (operation === 'saveContact') {
922
+ endpoint = '/save-contact';
923
+ body.device_id = this.getNodeParameter('deviceId', i);
924
+ body.name = this.getNodeParameter('name', i);
925
+ body.phone = this.getNodeParameter('phone', i);
926
+ const email = this.getNodeParameter('email', i);
927
+ if (email)
928
+ body.email = email;
929
+ const company = this.getNodeParameter('company', i);
930
+ if (company)
931
+ body.company = company;
932
+ }
933
+ else if (operation === 'saveContactsBulk') {
934
+ endpoint = '/save-contacts-bulk';
935
+ body.device_id = this.getNodeParameter('deviceId', i);
936
+ const contactsString = this.getNodeParameter('contacts', i);
937
+ try {
938
+ body.contacts = JSON.parse(contactsString);
939
+ }
940
+ catch (error) {
941
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Invalid JSON format for contacts');
942
+ }
943
+ }
944
+ }
945
+ else if (resource === 'package') {
946
+ if (operation === 'listPackages') {
947
+ endpoint = '/list-packages';
948
+ }
949
+ else if (operation === 'createDeposit') {
950
+ endpoint = '/create-deposit';
951
+ body.amount = this.getNodeParameter('amount', i);
952
+ body.payment_method = this.getNodeParameter('paymentMethod', i);
953
+ }
954
+ else if (operation === 'depositStatus') {
955
+ endpoint = '/deposit-status';
956
+ body.deposit_id = this.getNodeParameter('depositId', i);
957
+ }
958
+ }
959
+ else if (resource === 'user') {
960
+ if (operation === 'userInfo') {
961
+ endpoint = '/user-info';
962
+ }
963
+ }
964
+ else if (resource === 'security') {
965
+ if (operation === 'otpSecurityStatus') {
966
+ endpoint = '/otp-security-status';
967
+ }
968
+ else if (operation === 'merchantReputation') {
969
+ endpoint = '/merchant-reputation';
970
+ }
971
+ else if (operation === 'customerOtpStats') {
972
+ endpoint = '/customer-otp-stats';
973
+ }
974
+ }
975
+ else if (resource === 'utility') {
976
+ if (operation === 'testPhoneNormalization') {
977
+ endpoint = '/test-phone-normalization';
978
+ body.phone = this.getNodeParameter('phone', i);
979
+ // Remove auth fields for this endpoint
980
+ delete body.user_code;
981
+ delete body.secret;
982
+ }
983
+ }
984
+ const responseData = await GenericFunctions_1.kirimiApiRequest.call(this, method, endpoint, body);
985
+ returnData.push(responseData);
986
+ }
987
+ catch (error) {
988
+ if (this.continueOnFail()) {
989
+ returnData.push({ error: error.message });
990
+ continue;
991
+ }
992
+ throw error;
993
+ }
994
+ }
995
+ return [this.helpers.returnJsonArray(returnData)];
996
+ }
997
+ }
998
+ exports.Kirimi = Kirimi;
package/index.js ADDED
@@ -0,0 +1,7 @@
1
+ // This file is for development purposes only
2
+ // The actual exports are defined in package.json under the "n8n" field
3
+
4
+ module.exports = {
5
+ description: 'n8n community node for Kirimi WhatsApp Unofficial API',
6
+ version: '1.0.0'
7
+ };
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "n8n-nodes-kirimi",
3
+ "version": "1.0.0",
4
+ "description": "n8n community node for Kirimi WhatsApp Unofficial API",
5
+ "keywords": [
6
+ "n8n-community-node-package",
7
+ "n8n",
8
+ "kirimi",
9
+ "whatsapp",
10
+ "otp",
11
+ "messaging"
12
+ ],
13
+ "license": "MIT",
14
+ "homepage": "https://github.com/kiriminow/n8n-kirimi-nodes",
15
+ "author": {
16
+ "name": "Kirimi Support",
17
+ "email": "support@kirimi.id"
18
+ },
19
+ "repository": {
20
+ "type": "git",
21
+ "url": "https://github.com/kiriminow/n8n-kirimi-nodes.git"
22
+ },
23
+ "main": "index.js",
24
+ "scripts": {
25
+ "build": "tsc && gulp build:icons",
26
+ "dev": "tsc --watch",
27
+ "format": "prettier nodes credentials --write",
28
+ "lint": "eslint nodes/**/*.ts credentials/**/*.ts",
29
+ "lintfix": "eslint nodes/**/*.ts credentials/**/*.ts --fix",
30
+ "prepublishOnly": "npm run build && npm run lint -s"
31
+ },
32
+ "files": [
33
+ "dist"
34
+ ],
35
+ "n8n": {
36
+ "n8nNodesApiVersion": 1,
37
+ "credentials": [
38
+ "dist/credentials/KirimiApi.credentials.js"
39
+ ],
40
+ "nodes": [
41
+ "dist/nodes/Kirimi/Kirimi.node.js"
42
+ ]
43
+ },
44
+ "devDependencies": {
45
+ "@typescript-eslint/parser": "^5.45.0",
46
+ "eslint-plugin-n8n-nodes-base": "^1.11.0",
47
+ "gulp": "^4.0.2",
48
+ "n8n-workflow": "*",
49
+ "prettier": "^2.7.1",
50
+ "typescript": "^4.8.4"
51
+ },
52
+ "peerDependencies": {
53
+ "n8n-workflow": "*"
54
+ }
55
+ }