@green-api/greenapi-integration 0.6.0 → 0.6.1
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 +1080 -1061
- package/README.ru.md +1092 -1068
- package/dist/types/types.d.ts +14 -1
- package/package.json +42 -41
package/README.md
CHANGED
|
@@ -1,1061 +1,1080 @@
|
|
|
1
|
-
# Universal Integration Platform for GREEN-API
|
|
2
|
-
|
|
3
|
-
## Support links
|
|
4
|
-
|
|
5
|
-
[](mailto:support@greenapi.com)
|
|
6
|
-
[](https://t.me/greenapi_support_eng_bot)
|
|
7
|
-
[](https://wa.me/77273122366)
|
|
8
|
-
|
|
9
|
-
## Guides & News
|
|
10
|
-
|
|
11
|
-
[](https://www.youtube.com/@greenapi-en)
|
|
12
|
-
[](https://t.me/green_api)
|
|
13
|
-
[](https://whatsapp.com/channel/0029VaLj6J4LNSa2B5Jx6s3h)
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
- [
|
|
26
|
-
- [
|
|
27
|
-
- [
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
// Handle webhooks from
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
//
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
//
|
|
84
|
-
await adapter.
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
//
|
|
94
|
-
await adapter.
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
res.status(
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
res.status(
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
logger.
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
logger.
|
|
217
|
-
logger.
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
-
|
|
236
|
-
-
|
|
237
|
-
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
- `
|
|
245
|
-
- `
|
|
246
|
-
- `
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
"
|
|
256
|
-
"
|
|
257
|
-
"
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
"
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
"
|
|
291
|
-
"
|
|
292
|
-
"
|
|
293
|
-
"
|
|
294
|
-
"
|
|
295
|
-
"
|
|
296
|
-
"
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
```
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
```
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
}
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
```
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
const
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
//
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
router.post('/
|
|
613
|
-
try {
|
|
614
|
-
|
|
615
|
-
await
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
})
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
this.
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
const
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
}
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
const
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
}
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
// Set up
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
}
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1
|
+
# Universal Integration Platform for GREEN-API
|
|
2
|
+
|
|
3
|
+
## Support links
|
|
4
|
+
|
|
5
|
+
[](mailto:support@greenapi.com)
|
|
6
|
+
[](https://t.me/greenapi_support_eng_bot)
|
|
7
|
+
[](https://wa.me/77273122366)
|
|
8
|
+
|
|
9
|
+
## Guides & News
|
|
10
|
+
|
|
11
|
+
[](https://www.youtube.com/@greenapi-en)
|
|
12
|
+
[](https://t.me/green_api)
|
|
13
|
+
[](https://whatsapp.com/channel/0029VaLj6J4LNSa2B5Jx6s3h)
|
|
14
|
+
|
|
15
|
+
[](https://www.npmjs.com/package/@green-api/whatsapp-chatbot-js-v2)
|
|
16
|
+
[](https://opensource.org/licenses/MIT)
|
|
17
|
+
|
|
18
|
+
- [Документация на русском языке](./README.ru.md)
|
|
19
|
+
|
|
20
|
+
A flexible integration platform designed to simplify the process of connecting GREEN-API's WhatsApp gateway with various
|
|
21
|
+
third-party services.
|
|
22
|
+
|
|
23
|
+
## Table of Contents
|
|
24
|
+
|
|
25
|
+
- [Installation](#installation)
|
|
26
|
+
- [Core Components](#core-components)
|
|
27
|
+
- [Developer Guide](#developer-guide)
|
|
28
|
+
- [Working Example](#working-example)
|
|
29
|
+
- [Real-World Examples](#real-world-examples)
|
|
30
|
+
- [Best Practices](#best-practices)
|
|
31
|
+
|
|
32
|
+
## Installation
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
npm install @green-api/greenapi-integration
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Core Components
|
|
39
|
+
|
|
40
|
+
### 1. BaseAdapter
|
|
41
|
+
|
|
42
|
+
The foundation of your integration. Handles message & instance management, and platform-specific logic.
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
abstract class BaseAdapter<TPlatformWebhook, TPlatformMessage, TUser extends BaseUser = BaseUser, TInstance extends Instance = Instance> {
|
|
46
|
+
private readonly gaLogger = GreenApiLogger.getInstance(this.constructor.name);
|
|
47
|
+
|
|
48
|
+
public constructor(
|
|
49
|
+
transformer: MessageTransformer<TPlatformWebhook, TPlatformMessage>,
|
|
50
|
+
storage: StorageProvider<TUser, TInstance>,
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
public abstract createPlatformClient(params: any): Promise<any>;
|
|
54
|
+
|
|
55
|
+
public abstract sendToPlatform(message: TPlatformMessage, instance: TInstance): Promise<void>;
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
#### Methods
|
|
60
|
+
|
|
61
|
+
When extending BaseAdapter, your implementation has access to several methods:
|
|
62
|
+
|
|
63
|
+
##### Webhook Handling
|
|
64
|
+
|
|
65
|
+
These webhook handling methods call your message transformation methods automatically, without the need to use them
|
|
66
|
+
directly in your code.
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
// Handle webhooks from your platform
|
|
70
|
+
await adapter.handlePlatformWebhook(webhookData, instanceId);
|
|
71
|
+
|
|
72
|
+
// Handle webhooks from GREEN-API. The second parameter is telling the function to handle only specific webhooks.
|
|
73
|
+
// The second parameter must be specified, otherwise webhooks will not be processed.
|
|
74
|
+
await adapter.handleGreenApiWebhook(webhook, ['incomingMessageReceived']);
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
##### Instance Management
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
// Create new instance
|
|
81
|
+
const instance = await adapter.createInstance(instanceData, settings, userEmail);
|
|
82
|
+
|
|
83
|
+
// Get instance details
|
|
84
|
+
const details = await adapter.getInstance(instanceId);
|
|
85
|
+
|
|
86
|
+
// Remove instance
|
|
87
|
+
await adapter.removeInstance(instanceId);
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
##### User Management
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
// Create new user
|
|
94
|
+
const user = await adapter.createUser(userEmail, userData);
|
|
95
|
+
|
|
96
|
+
// Update user
|
|
97
|
+
await adapter.updateUser(userEmail, updateData);
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
#### Webhook Implementation Example
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
// Platform webhook endpoint
|
|
104
|
+
app.post('/webhook/platform', async (req, res) => {
|
|
105
|
+
try {
|
|
106
|
+
await adapter.handlePlatformWebhook(req.body, instanceId);
|
|
107
|
+
res.status(200).send();
|
|
108
|
+
} catch (error) {
|
|
109
|
+
console.error('Failed to handle platform webhook:', error);
|
|
110
|
+
res.status(500).send();
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
// GREEN-API webhook endpoint
|
|
115
|
+
app.post('/webhook/green-api', async (req, res) => {
|
|
116
|
+
try {
|
|
117
|
+
// Process specific webhook types
|
|
118
|
+
await adapter.handleGreenApiWebhook(req.body, [
|
|
119
|
+
'incomingMessageReceived',
|
|
120
|
+
'outgoingMessageStatus'
|
|
121
|
+
]);
|
|
122
|
+
res.status(200).send();
|
|
123
|
+
} catch (error) {
|
|
124
|
+
console.error('Failed to handle GREEN-API webhook:', error);
|
|
125
|
+
res.status(500).send();
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### 2. MessageTransformer
|
|
131
|
+
|
|
132
|
+
Handles message format conversion between GREEN-API and your platform.
|
|
133
|
+
|
|
134
|
+
```typescript
|
|
135
|
+
abstract class MessageTransformer<TPlatformWebhook, TPlatformMessage> {
|
|
136
|
+
abstract toPlatformMessage(webhook: GreenApiWebhook): TPlatformMessage;
|
|
137
|
+
|
|
138
|
+
abstract toGreenApiMessage(message: TPlatformWebhook): Message;
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### 3. StorageProvider
|
|
143
|
+
|
|
144
|
+
Interface for data persistence operations.
|
|
145
|
+
|
|
146
|
+
```typescript
|
|
147
|
+
abstract class StorageProvider<
|
|
148
|
+
TUser extends BaseUser = BaseUser,
|
|
149
|
+
TInstance extends Instance = Instance,
|
|
150
|
+
TUserCreate extends Record<string, any> = any,
|
|
151
|
+
TUserUpdate extends Record<string, any> = any
|
|
152
|
+
> {
|
|
153
|
+
abstract createInstance(instance: Instance): Promise<TInstance>;
|
|
154
|
+
|
|
155
|
+
abstract getInstance(idInstance: number | bigint): Promise<TInstance | null>;
|
|
156
|
+
|
|
157
|
+
abstract removeInstance(instanceId: number | bigint): Promise<TInstance>;
|
|
158
|
+
|
|
159
|
+
abstract createUser(data: TUserCreate): Promise<TUser>;
|
|
160
|
+
|
|
161
|
+
abstract findUser(identifier: string): Promise<TUser | null>;
|
|
162
|
+
|
|
163
|
+
abstract updateUser(identifier: string, data: Partial<TUserUpdate>): Promise<TUser>;
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### 4. BaseGreenApiAuthGuard
|
|
168
|
+
|
|
169
|
+
Handles webhook authentication for incoming GREEN-API requests.
|
|
170
|
+
|
|
171
|
+
```typescript
|
|
172
|
+
abstract class BaseGreenApiAuthGuard<T extends BaseRequest = BaseRequest> {
|
|
173
|
+
private readonly gaLogger = GreenApiLogger.getInstance(this.constructor.name);
|
|
174
|
+
|
|
175
|
+
constructor(protected storage: StorageProvider);
|
|
176
|
+
|
|
177
|
+
// Validates incoming webhook requests
|
|
178
|
+
async validateRequest(request: T): Promise<boolean>;
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
Example implementation of `BaseGreenApiAuthGuard`:
|
|
183
|
+
|
|
184
|
+
```typescript
|
|
185
|
+
class YourAuthGuard extends BaseGreenApiAuthGuard<YourRequest> {
|
|
186
|
+
constructor(storage: StorageProvider) {
|
|
187
|
+
super(storage);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Using with Express
|
|
192
|
+
app.post('/webhook', async (req, res) => {
|
|
193
|
+
const guard = new YourAuthGuard(storage);
|
|
194
|
+
try {
|
|
195
|
+
await guard.validateRequest(req);
|
|
196
|
+
// Process webhook
|
|
197
|
+
} catch (error) {
|
|
198
|
+
if (error instanceof AuthenticationError) {
|
|
199
|
+
res.status(401).json({error: error.message});
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
res.status(500).json({error: 'Internal server error'});
|
|
203
|
+
}
|
|
204
|
+
});
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### 5. GreenApiLogger
|
|
208
|
+
|
|
209
|
+
A structured JSON logger with colored output. Provides consistent logging format across your application with
|
|
210
|
+
proper error handling and serialization support.
|
|
211
|
+
|
|
212
|
+
```typescript
|
|
213
|
+
const logger = GreenApiLogger.getInstance("YourComponent");
|
|
214
|
+
|
|
215
|
+
// Basic logging
|
|
216
|
+
logger.debug("Debug message", {someContext: "value"});
|
|
217
|
+
logger.info("Info message", {userId: 123});
|
|
218
|
+
logger.warn("Warning message", {alert: true});
|
|
219
|
+
logger.error("Error occurred", {errorCode: 500});
|
|
220
|
+
logger.fatal("Fatal error", {critical: true});
|
|
221
|
+
|
|
222
|
+
// Error logging with full context
|
|
223
|
+
try {
|
|
224
|
+
await someOperation();
|
|
225
|
+
} catch (error) {
|
|
226
|
+
logger.logErrorResponse(error, "Operation failed", {
|
|
227
|
+
operationId: "123",
|
|
228
|
+
additionalInfo: "some context"
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
#### Features
|
|
234
|
+
|
|
235
|
+
- Structured JSON logging with consistent format
|
|
236
|
+
- Colored output based on log level (debug=cyan, info=green, warn=yellow, error=red, fatal=magenta)
|
|
237
|
+
- Built-in error handling with stack trace formatting
|
|
238
|
+
- Automatic serialization
|
|
239
|
+
- Framework agnostic - works with any Node.js application
|
|
240
|
+
- Special handling for Axios errors with detailed request/response info
|
|
241
|
+
|
|
242
|
+
#### Log Levels
|
|
243
|
+
|
|
244
|
+
- `debug` - Detailed information for debugging
|
|
245
|
+
- `info` - General information about system operation
|
|
246
|
+
- `warn` - Warning messages for potentially harmful situations
|
|
247
|
+
- `error` - Error messages for serious problems
|
|
248
|
+
- `fatal` - Critical errors that require immediate attention
|
|
249
|
+
- `log` - Alternative to info (for compatibility)
|
|
250
|
+
|
|
251
|
+
#### Output Format
|
|
252
|
+
|
|
253
|
+
```json
|
|
254
|
+
{
|
|
255
|
+
"timestamp": "30/01/2025, 04:34:49",
|
|
256
|
+
"level": "error",
|
|
257
|
+
"context": "CoreService",
|
|
258
|
+
"message": "Operation failed",
|
|
259
|
+
"error": "Failed to process request",
|
|
260
|
+
"stack": [
|
|
261
|
+
"Error: Failed to process request",
|
|
262
|
+
" at CoreService.process (/app/service.js:123:45)",
|
|
263
|
+
" at async Router.handle (/app/router.js:67:89)"
|
|
264
|
+
],
|
|
265
|
+
"additionalContext": {
|
|
266
|
+
"requestId": "abc-123",
|
|
267
|
+
"userId": "user_456"
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
#### Error Handling
|
|
273
|
+
|
|
274
|
+
```typescript
|
|
275
|
+
// Axios error handling
|
|
276
|
+
try {
|
|
277
|
+
await apiRequest();
|
|
278
|
+
} catch (error) {
|
|
279
|
+
logger.logErrorResponse(error, "API Request failed", {
|
|
280
|
+
endpoint: "/users",
|
|
281
|
+
method: "POST"
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
// Will output detailed API error info:
|
|
287
|
+
|
|
288
|
+
```
|
|
289
|
+
{
|
|
290
|
+
"timestamp": "30/01/2025, 04:34:49",
|
|
291
|
+
"level": "error",
|
|
292
|
+
"context": "ApiService",
|
|
293
|
+
"message": "API Request failed - API Error:",
|
|
294
|
+
"status": 400,
|
|
295
|
+
"statusText": "Bad Request",
|
|
296
|
+
"data": { "error": "Invalid input" },
|
|
297
|
+
"url": "https://api.example.com/users",
|
|
298
|
+
"method": "POST",
|
|
299
|
+
"endpoint": "/users"
|
|
300
|
+
}
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
#### Using with Frameworks
|
|
304
|
+
|
|
305
|
+
The logger is framework-agnostic but can be easily integrated with any framework:
|
|
306
|
+
|
|
307
|
+
```typescript
|
|
308
|
+
// Express example
|
|
309
|
+
app.use((err, req, res, next) => {
|
|
310
|
+
const logger = GreenApiLogger.getInstance("Express");
|
|
311
|
+
logger.error("Request failed", {
|
|
312
|
+
path: req.path,
|
|
313
|
+
method: req.method,
|
|
314
|
+
error: err.message
|
|
315
|
+
});
|
|
316
|
+
next(err);
|
|
317
|
+
});
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
#### Important Note on Logger Usage
|
|
321
|
+
|
|
322
|
+
While you can use this logger alongside other logging solutions, it's recommended to disable your
|
|
323
|
+
framework's built-in logger to avoid duplicate or malformed logs.
|
|
324
|
+
|
|
325
|
+
For example, when using NestJS, you can disable its built-in logger like this:
|
|
326
|
+
|
|
327
|
+
```typescript
|
|
328
|
+
// main.ts
|
|
329
|
+
const app = await NestFactory.create(AppModule, {
|
|
330
|
+
logger: false // Disable NestJS logger
|
|
331
|
+
});
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
And then use it in your class like this:
|
|
335
|
+
|
|
336
|
+
```typescript
|
|
337
|
+
gaLogger = GreenApiLogger.getInstance(YourClass.name);
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
#### Methods
|
|
341
|
+
|
|
342
|
+
##### Basic Logging Methods
|
|
343
|
+
|
|
344
|
+
- `debug(message: string, context?: Record<string, any>)`: Log debug level message
|
|
345
|
+
- `info(message: string, context?: Record<string, any>)`: Log info level message
|
|
346
|
+
- `warn(message: string, context?: Record<string, any>)`: Log warning level message
|
|
347
|
+
- `error(message: string, context?: Record<string, any>)`: Log error level message
|
|
348
|
+
- `fatal(message: string, context?: Record<string, any>)`: Log fatal level message
|
|
349
|
+
- `log(message: string, context?: string)`: Alternative to info method
|
|
350
|
+
|
|
351
|
+
##### Special Methods
|
|
352
|
+
|
|
353
|
+
- `logErrorResponse(error: any, context: string, additionalContext?: Record<string, any>)`:
|
|
354
|
+
Enhanced error logging with special handling for Axios errors and stack traces
|
|
355
|
+
|
|
356
|
+
##### Utility Methods
|
|
357
|
+
|
|
358
|
+
- `getInstance(context: string = "Global"): GreenApiLogger`: Get or create logger instance for specified context
|
|
359
|
+
|
|
360
|
+
#### Best Practices
|
|
361
|
+
|
|
362
|
+
1. **Use Consistent Context Names**
|
|
363
|
+
|
|
364
|
+
```typescript
|
|
365
|
+
// In your component/service
|
|
366
|
+
private readonly
|
|
367
|
+
logger = GreenApiLogger.getInstance(YourService.name);
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
2. **Include Relevant Context**
|
|
371
|
+
|
|
372
|
+
```typescript
|
|
373
|
+
logger.info("User action completed", {
|
|
374
|
+
userId: user.id,
|
|
375
|
+
action: "profile_update",
|
|
376
|
+
duration: timeTaken
|
|
377
|
+
});
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
3. **Proper Error Handling**
|
|
381
|
+
|
|
382
|
+
```typescript
|
|
383
|
+
try {
|
|
384
|
+
await complexOperation();
|
|
385
|
+
} catch (error) {
|
|
386
|
+
logger.logErrorResponse(error, "Complex operation failed", {
|
|
387
|
+
operationId: id,
|
|
388
|
+
parameters: params
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
4. **Use Appropriate Log Levels**
|
|
394
|
+
|
|
395
|
+
```typescript
|
|
396
|
+
// Debug for detailed information
|
|
397
|
+
logger.debug("Processing chunk", {chunkId: 123, size: 1024});
|
|
398
|
+
|
|
399
|
+
// Info for general operation
|
|
400
|
+
logger.info("User logged in", {userId: 456});
|
|
401
|
+
|
|
402
|
+
// Warn for potential issues
|
|
403
|
+
logger.warn("High memory usage", {memoryUsage: "85%"});
|
|
404
|
+
|
|
405
|
+
// Error for actual problems
|
|
406
|
+
logger.error("Database connection failed", {dbHost: "primary"});
|
|
407
|
+
|
|
408
|
+
// Fatal for critical issues
|
|
409
|
+
logger.fatal("System shutdown required", {reason: "data corruption"});
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
### 6. GreenApiClient
|
|
413
|
+
|
|
414
|
+
Direct interface to GREEN-API methods.
|
|
415
|
+
|
|
416
|
+
```typescript
|
|
417
|
+
const client = new GreenApiClient({
|
|
418
|
+
idInstance: 'your_instance_id',
|
|
419
|
+
apiTokenInstance: 'your_token'
|
|
420
|
+
});
|
|
421
|
+
|
|
422
|
+
// Examples:
|
|
423
|
+
await client.setProfilePicture(fileBlob);
|
|
424
|
+
await client.getAuthorizationCode(phoneNumber);
|
|
425
|
+
await client.getQR();
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
## Developer Guide
|
|
429
|
+
|
|
430
|
+
This guide will walk you through creating your first integration with GREEN-API's WhatsApp gateway.
|
|
431
|
+
|
|
432
|
+
### Project Structure
|
|
433
|
+
|
|
434
|
+
```
|
|
435
|
+
your-integration/
|
|
436
|
+
├── src/
|
|
437
|
+
│ ├── core/
|
|
438
|
+
│ │ ├── adapter.ts # Your platform adapter
|
|
439
|
+
│ │ ├── transformer.ts # Message transformer
|
|
440
|
+
│ │ ├── storage.ts # Data storage implementation
|
|
441
|
+
│ │ └── router.ts # Webhook endpoints
|
|
442
|
+
│ ├── types/
|
|
443
|
+
│ │ └── types.ts # Platform-specific types
|
|
444
|
+
│ └── main.ts # Main exports
|
|
445
|
+
├── package.json
|
|
446
|
+
└── tsconfig.json
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
```mermaid
|
|
450
|
+
graph TB
|
|
451
|
+
subgraph "WhatsApp to Platform"
|
|
452
|
+
WA[WhatsApp] -->|Send message| GA1[GREEN-API]
|
|
453
|
+
GA1 -->|Webhook| INT1[Your Integration]
|
|
454
|
+
INT1 -->|1 . Validate webhook| GD1[BaseGreenApiAuthGuard]
|
|
455
|
+
INT1 -->|2 . Transform message| TR1[MessageTransformer]
|
|
456
|
+
INT1 -->|3 . Send to platform| PL1[Your Platform]
|
|
457
|
+
end
|
|
458
|
+
|
|
459
|
+
subgraph "Platform to WhatsApp"
|
|
460
|
+
PL2[Your Platform] -->|Webhook| INT2[Your Integration]
|
|
461
|
+
INT2 -->|1 . Transform message| TR2[MessageTransformer]
|
|
462
|
+
INT2 -->|2 . Send via API| GA2[GREEN-API]
|
|
463
|
+
GA2 -->|Send message| WA2[WhatsApp]
|
|
464
|
+
end
|
|
465
|
+
|
|
466
|
+
subgraph "Components"
|
|
467
|
+
style Components fill: #f9f9f9, stroke: #333, stroke-width: 2px
|
|
468
|
+
TR[MessageTransformer]
|
|
469
|
+
ST[StorageProvider]
|
|
470
|
+
AD[BaseAdapter]
|
|
471
|
+
GD[WebhookGuard]
|
|
472
|
+
end
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
### Implementation Steps
|
|
476
|
+
|
|
477
|
+
#### Step 1: Define Platform Types
|
|
478
|
+
|
|
479
|
+
First, define the message types for your platform:
|
|
480
|
+
|
|
481
|
+
```typescript
|
|
482
|
+
// types/types.ts
|
|
483
|
+
export interface YourPlatformWebhook {
|
|
484
|
+
id: string;
|
|
485
|
+
from: string;
|
|
486
|
+
message: string;
|
|
487
|
+
timestamp: number;
|
|
488
|
+
// Add other platform-specific fields
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
export interface YourPlatformMessage {
|
|
492
|
+
recipient: string;
|
|
493
|
+
content: string;
|
|
494
|
+
// Add other platform-specific fields
|
|
495
|
+
}
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
#### Step 2: Create Message Transformer
|
|
499
|
+
|
|
500
|
+
Create a transformer that converts messages between your platform's format and GREEN-API's format:
|
|
501
|
+
|
|
502
|
+
```typescript
|
|
503
|
+
// core/transformer.ts
|
|
504
|
+
import { MessageTransformer, Message, GreenApiWebhook } from '@green-api/greenapi-integration';
|
|
505
|
+
import { YourPlatformWebhook, YourPlatformMessage } from '../types/types';
|
|
506
|
+
|
|
507
|
+
export class YourTransformer extends MessageTransformer<YourPlatformWebhook, YourPlatformMessage> {
|
|
508
|
+
toPlatformMessage(webhook: GreenApiWebhook): YourPlatformMessage {
|
|
509
|
+
// Transform GREEN-API webhook to your platform format
|
|
510
|
+
return {
|
|
511
|
+
recipient: webhook.senderData.sender,
|
|
512
|
+
content: webhook.messageData.textMessageData?.textMessage || '',
|
|
513
|
+
};
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
toGreenApiMessage(message: YourPlatformWebhook): Message {
|
|
517
|
+
// Transform your platform webhook to GREEN-API format
|
|
518
|
+
return {
|
|
519
|
+
type: 'text',
|
|
520
|
+
chatId: message.from,
|
|
521
|
+
message: message.message,
|
|
522
|
+
};
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
#### Step 3: Implement Storage Provider
|
|
528
|
+
|
|
529
|
+
Create a storage provider to manage users and instances. You can use any database or ORM:
|
|
530
|
+
|
|
531
|
+
```typescript
|
|
532
|
+
// core/storage.ts
|
|
533
|
+
import { StorageProvider, BaseUser, Instance, Settings } from '@green-api/greenapi-integration';
|
|
534
|
+
import { PrismaClient } from '@prisma/client'; // Or your database client
|
|
535
|
+
|
|
536
|
+
export class YourStorage extends StorageProvider {
|
|
537
|
+
private db: PrismaClient;
|
|
538
|
+
|
|
539
|
+
constructor() {
|
|
540
|
+
this.db = new PrismaClient();
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
async findUserByEmail(email: string) {
|
|
544
|
+
return this.db.user.findUnique({where: {email}});
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
async createInstance(instance: Instance) {
|
|
548
|
+
return this.db.instance.create({
|
|
549
|
+
data: {
|
|
550
|
+
idInstance: instance.idInstance,
|
|
551
|
+
apiTokenInstance: instance.apiTokenInstance,
|
|
552
|
+
userId: instance.userId,
|
|
553
|
+
settings: instance.settings || {},
|
|
554
|
+
},
|
|
555
|
+
});
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
// Implement other required methods
|
|
559
|
+
}
|
|
560
|
+
```
|
|
561
|
+
|
|
562
|
+
#### Step 4: Create Your Platform Adapter
|
|
563
|
+
|
|
564
|
+
The adapter handles the actual communication between platforms:
|
|
565
|
+
|
|
566
|
+
```typescript
|
|
567
|
+
// core/adapter.ts
|
|
568
|
+
import { BaseAdapter, BaseInstance } from '@green-api/greenapi-integration';
|
|
569
|
+
import { YourPlatformClient } from 'your-platform-sdk';
|
|
570
|
+
import { YourPlatformWebhook, YourPlatformMessage } from '../types/types';
|
|
571
|
+
|
|
572
|
+
export class YourAdapter extends BaseAdapter<YourPlatformWebhook, YourPlatformMessage> {
|
|
573
|
+
async createPlatformClient(config: { apiKey: string, apiUrl: string }) {
|
|
574
|
+
return new YourPlatformClient({
|
|
575
|
+
baseUrl: config.apiUrl,
|
|
576
|
+
apiKey: config.apiKey,
|
|
577
|
+
});
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
async sendToPlatform(message: YourPlatformMessage, instance: Instance) {
|
|
581
|
+
const client = await this.createPlatformClient(instance.config);
|
|
582
|
+
await client.sendMessage(message);
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
```
|
|
586
|
+
|
|
587
|
+
#### Step 5: Implement Webhook Controller
|
|
588
|
+
|
|
589
|
+
Define webhook endpoints that your application will listen to:
|
|
590
|
+
|
|
591
|
+
```typescript
|
|
592
|
+
// core/webhook.ts
|
|
593
|
+
import express from 'express';
|
|
594
|
+
import { YourAdapter } from '../core/adapter';
|
|
595
|
+
import { YourTransformer } from '../core/transformer';
|
|
596
|
+
import { YourStorage } from '../core/storage';
|
|
597
|
+
|
|
598
|
+
const router = express.Router();
|
|
599
|
+
const storage = new YourStorage();
|
|
600
|
+
const transformer = new YourTransformer();
|
|
601
|
+
const adapter = new YourAdapter(transformer, storage);
|
|
602
|
+
|
|
603
|
+
class WebhookGuard extends BaseGreenApiAuthGuard {
|
|
604
|
+
constructor(storage: StorageProvider) {
|
|
605
|
+
super(storage);
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
const guard = new WebhookGuard(storage);
|
|
610
|
+
|
|
611
|
+
// Webhook endpoints
|
|
612
|
+
router.post('/green-api', async (req, res) => {
|
|
613
|
+
try {
|
|
614
|
+
// Validate webhook first
|
|
615
|
+
await guard.validateRequest(req);
|
|
616
|
+
|
|
617
|
+
// Process webhook if validation passed
|
|
618
|
+
// As the second parameter, specfify the types of webhooks to be processed (otherwise skipped)
|
|
619
|
+
await adapter.handleGreenApiWebhook(req.body, ['incomingMessageReceived']);
|
|
620
|
+
res.status(200).json({status: 'ok'});
|
|
621
|
+
} catch (error) {
|
|
622
|
+
if (error instanceof AuthenticationError) {
|
|
623
|
+
res.status(401).json({error: error.message});
|
|
624
|
+
return;
|
|
625
|
+
}
|
|
626
|
+
console.error('Webhook error:', error);
|
|
627
|
+
res.status(500).json({error: 'Internal server error'});
|
|
628
|
+
}
|
|
629
|
+
});
|
|
630
|
+
|
|
631
|
+
router.post('/platform', async (req, res) => {
|
|
632
|
+
try {
|
|
633
|
+
const instanceId = req.query.instanceId;
|
|
634
|
+
await adapter.handlePlatformWebhook(req.body, instanceId);
|
|
635
|
+
res.status(200).json({status: 'ok'});
|
|
636
|
+
} catch (error) {
|
|
637
|
+
console.error('Platform webhook error:', error);
|
|
638
|
+
res.status(500).json({error: 'Internal server error'});
|
|
639
|
+
}
|
|
640
|
+
});
|
|
641
|
+
|
|
642
|
+
router.post('/instance', async (req, res) => {
|
|
643
|
+
try {
|
|
644
|
+
const {idInstance, apiTokenInstance, userEmail} = req.body;
|
|
645
|
+
|
|
646
|
+
if (!idInstance || !apiTokenInstance || !userEmail) {
|
|
647
|
+
throw new BadRequestError('Required fields missing');
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
const user = await storage.findUserByEmail(userEmail);
|
|
651
|
+
const instance = await adapter.createInstance({
|
|
652
|
+
idInstance: Number(idInstance),
|
|
653
|
+
apiTokenInstance,
|
|
654
|
+
settings: {
|
|
655
|
+
webhookUrl: `${process.env.APP_URL}/webhook/green-api`,
|
|
656
|
+
webhookUrlToken: `token_${Date.now()}`,
|
|
657
|
+
incomingWebhook: 'yes'
|
|
658
|
+
},
|
|
659
|
+
userId: user.id
|
|
660
|
+
});
|
|
661
|
+
|
|
662
|
+
res.status(200).json({
|
|
663
|
+
status: 'ok',
|
|
664
|
+
data: instance,
|
|
665
|
+
message: 'Instance created successfully. Please wait 2 minutes for settings to apply.'
|
|
666
|
+
});
|
|
667
|
+
|
|
668
|
+
} catch (error) {
|
|
669
|
+
console.error('Instance creation error:', error);
|
|
670
|
+
res.status(500).json({error: 'Failed to create instance'});
|
|
671
|
+
}
|
|
672
|
+
});
|
|
673
|
+
|
|
674
|
+
export default router;
|
|
675
|
+
```
|
|
676
|
+
|
|
677
|
+
#### Step 6: Create Application Entry Point
|
|
678
|
+
|
|
679
|
+
Put it all together in your entrypoint:
|
|
680
|
+
|
|
681
|
+
```typescript
|
|
682
|
+
// main.ts
|
|
683
|
+
import express from 'express';
|
|
684
|
+
import bodyParser from 'body-parser';
|
|
685
|
+
import dotenv from 'dotenv';
|
|
686
|
+
import webhookRouter from './controllers/webhook';
|
|
687
|
+
import { YourAdapter } from './core/adapter';
|
|
688
|
+
import { YourTransformer } from './core/transformer';
|
|
689
|
+
import { YourStorage } from './core/storage';
|
|
690
|
+
|
|
691
|
+
// Load environment variables
|
|
692
|
+
dotenv.config();
|
|
693
|
+
|
|
694
|
+
async function bootstrap() {
|
|
695
|
+
// Initialize components
|
|
696
|
+
const storage = new YourStorage();
|
|
697
|
+
const transformer = new YourTransformer();
|
|
698
|
+
const adapter = new YourAdapter(transformer, storage);
|
|
699
|
+
|
|
700
|
+
// Create Express application
|
|
701
|
+
const app = express();
|
|
702
|
+
app.use(bodyParser.json());
|
|
703
|
+
|
|
704
|
+
// Set up webhook routes
|
|
705
|
+
app.use('/webhook', webhookRouter);
|
|
706
|
+
|
|
707
|
+
// Start server
|
|
708
|
+
const port = process.env.PORT || 3000;
|
|
709
|
+
app.listen(port, () => {
|
|
710
|
+
console.log(`Server running on port ${port}`);
|
|
711
|
+
});
|
|
712
|
+
|
|
713
|
+
console.log('Integration platform ready!');
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
// Handle errors
|
|
717
|
+
bootstrap();
|
|
718
|
+
```
|
|
719
|
+
|
|
720
|
+
### Publishing Your Integration
|
|
721
|
+
|
|
722
|
+
1. **Prepare package.json**
|
|
723
|
+
|
|
724
|
+
```json
|
|
725
|
+
{
|
|
726
|
+
"name": "greenapi-integration-yourplatform",
|
|
727
|
+
"version": "1.0.0",
|
|
728
|
+
"main": "dist/index.js",
|
|
729
|
+
"types": "dist/index.d.ts",
|
|
730
|
+
"scripts": {
|
|
731
|
+
"build": "tsc",
|
|
732
|
+
"prepublishOnly": "npm run build"
|
|
733
|
+
},
|
|
734
|
+
"dependencies": {
|
|
735
|
+
"@green-api/greenapi-integration": "^0.4.0",
|
|
736
|
+
"express": "^4.18.2"
|
|
737
|
+
// other dependencies
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
```
|
|
741
|
+
|
|
742
|
+
2. **Build and Publish**
|
|
743
|
+
|
|
744
|
+
```bash
|
|
745
|
+
npm run build
|
|
746
|
+
npm publish
|
|
747
|
+
```
|
|
748
|
+
|
|
749
|
+
## Working Example
|
|
750
|
+
|
|
751
|
+
Check out the `/examples/custom-adapter` directory for a complete working example showing:
|
|
752
|
+
|
|
753
|
+
- Two-way message flow between WhatsApp and a custom platform
|
|
754
|
+
- Webhook handling
|
|
755
|
+
- Instance setup and configuration
|
|
756
|
+
- Message transformation
|
|
757
|
+
- Error handling
|
|
758
|
+
|
|
759
|
+
### Running the Example
|
|
760
|
+
|
|
761
|
+
1. Clone the repository
|
|
762
|
+
2. Update .env with your GREEN-API credentials:
|
|
763
|
+
|
|
764
|
+
```env
|
|
765
|
+
VISITOR_ID_INSTANCE=your_visitor_instance_id
|
|
766
|
+
VISITOR_API_TOKEN=your_visitor_instance_token
|
|
767
|
+
AGENT_ID_INSTANCE=your_agent_instance_id
|
|
768
|
+
AGENT_API_TOKEN=your_agent_instance_token
|
|
769
|
+
AGENT_PHONE_NUMBER=your_agent_phone_number
|
|
770
|
+
WEBHOOK_URL=your_webhook_url
|
|
771
|
+
PORT=3000
|
|
772
|
+
```
|
|
773
|
+
|
|
774
|
+
3. Install dependencies and run:
|
|
775
|
+
|
|
776
|
+
```bash
|
|
777
|
+
cd examples/custom-adapter
|
|
778
|
+
npm install
|
|
779
|
+
npm start
|
|
780
|
+
```
|
|
781
|
+
|
|
782
|
+
## Complete Example Implementation
|
|
783
|
+
|
|
784
|
+
### Project Structure
|
|
785
|
+
|
|
786
|
+
```
|
|
787
|
+
examples/
|
|
788
|
+
└── custom-adapter/
|
|
789
|
+
├── src/
|
|
790
|
+
│ ├── main.ts
|
|
791
|
+
│ ├── simple-adapter.ts
|
|
792
|
+
│ ├── simple-transformer.ts
|
|
793
|
+
│ ├── simple-storage.ts
|
|
794
|
+
│ └── types.ts
|
|
795
|
+
├── .env
|
|
796
|
+
└── package.json
|
|
797
|
+
```
|
|
798
|
+
|
|
799
|
+
### types.ts
|
|
800
|
+
|
|
801
|
+
```typescript
|
|
802
|
+
interface SimplePlatformWebhook {
|
|
803
|
+
messageId: string;
|
|
804
|
+
from: string;
|
|
805
|
+
text: string;
|
|
806
|
+
timestamp: number;
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
interface SimplePlatformMessage {
|
|
810
|
+
to: string;
|
|
811
|
+
content: string;
|
|
812
|
+
replyTo?: string;
|
|
813
|
+
}
|
|
814
|
+
```
|
|
815
|
+
|
|
816
|
+
### simple-transformer.ts
|
|
817
|
+
|
|
818
|
+
```typescript
|
|
819
|
+
import {
|
|
820
|
+
MessageTransformer,
|
|
821
|
+
Message,
|
|
822
|
+
GreenApiWebhook,
|
|
823
|
+
formatPhoneNumber,
|
|
824
|
+
IntegrationError,
|
|
825
|
+
} from "@green-api/greenapi-integration";
|
|
826
|
+
import { SimplePlatformMessage, SimplePlatformWebhook } from "./types";
|
|
827
|
+
|
|
828
|
+
export class SimpleTransformer extends MessageTransformer<SimplePlatformWebhook, SimplePlatformMessage> {
|
|
829
|
+
toPlatformMessage(webhook: GreenApiWebhook): SimplePlatformMessage {
|
|
830
|
+
if (webhook.typeWebhook === "incomingMessageReceived") {
|
|
831
|
+
if (webhook.messageData.typeMessage !== "extendedTextMessage") {
|
|
832
|
+
throw new IntegrationError("Only text messages are supported", "BAD_REQUEST_ERROR", 400);
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
return {
|
|
836
|
+
to: webhook.senderData.sender,
|
|
837
|
+
content: webhook.messageData.extendedTextMessageData?.text || "",
|
|
838
|
+
};
|
|
839
|
+
}
|
|
840
|
+
throw new IntegrationError("Only incomingMessageReceived type webhooks are supported", "INTEGRATION_ERROR", 500);
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
toGreenApiMessage(message: SimplePlatformWebhook): Message {
|
|
844
|
+
return {
|
|
845
|
+
type: "text",
|
|
846
|
+
chatId: formatPhoneNumber(message.from),
|
|
847
|
+
message: message.text,
|
|
848
|
+
};
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
```
|
|
852
|
+
|
|
853
|
+
### simple-storage.ts
|
|
854
|
+
|
|
855
|
+
```typescript
|
|
856
|
+
import { StorageProvider, BaseUser, Instance } from '@green-api/greenapi-integration';
|
|
857
|
+
|
|
858
|
+
export class SimpleStorage extends StorageProvider {
|
|
859
|
+
private users: Map<string, BaseUser> = new Map();
|
|
860
|
+
private instances: Map<number, Instance> = new Map();
|
|
861
|
+
|
|
862
|
+
async createInstance(instance: Instance, userId: bigint): Promise<Instance> {
|
|
863
|
+
this.instances.set(Number(instance.idInstance), {
|
|
864
|
+
...instance,
|
|
865
|
+
});
|
|
866
|
+
return instance;
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
async getInstance(idInstance: number): Promise<Instance | null> {
|
|
870
|
+
return this.instances.get(idInstance) || null;
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
async removeInstance(instanceId: number): Promise<Instance> {
|
|
874
|
+
const instance = this.instances.get(instanceId);
|
|
875
|
+
if (!instance) throw new Error('Instance not found');
|
|
876
|
+
this.instances.delete(instanceId);
|
|
877
|
+
return instance;
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
async createUser(data: any): Promise<BaseUser> {
|
|
881
|
+
const user = {id: Date.now(), ...data};
|
|
882
|
+
this.users.set(data.email, user);
|
|
883
|
+
return user;
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
async findUser(identifier: string): Promise<BaseUser | null> {
|
|
887
|
+
return this.users.get(identifier) || null;
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
async updateUser(identifier: string, data: any): Promise<BaseUser> {
|
|
891
|
+
const user = await this.findUser(identifier);
|
|
892
|
+
if (!user) throw new Error('User not found');
|
|
893
|
+
const updated = {...user, ...data};
|
|
894
|
+
this.users.set(identifier, updated);
|
|
895
|
+
return updated;
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
```
|
|
899
|
+
|
|
900
|
+
### simple-adapter.ts
|
|
901
|
+
|
|
902
|
+
```typescript
|
|
903
|
+
import { BaseAdapter, Instance } from "@green-api/greenapi-integration";
|
|
904
|
+
import { SimplePlatformMessage, SimplePlatformWebhook } from "./types";
|
|
905
|
+
import axios from 'axios';
|
|
906
|
+
|
|
907
|
+
export class SimpleAdapter extends BaseAdapter<SimplePlatformWebhook, SimplePlatformMessage> {
|
|
908
|
+
async createPlatformClient(config: { apiKey: string, apiUrl: string }) {
|
|
909
|
+
return axios.create({
|
|
910
|
+
baseURL: config.apiUrl,
|
|
911
|
+
headers: {
|
|
912
|
+
'Authorization': `Bearer ${config.apiKey}`,
|
|
913
|
+
'Content-Type': 'application/json'
|
|
914
|
+
}
|
|
915
|
+
});
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
async sendToPlatform(message: SimplePlatformMessage, instance: Instance): Promise<void> {
|
|
919
|
+
// In a real implementation, we would send to the platform
|
|
920
|
+
// For demo, we'll just log and simulate a response
|
|
921
|
+
console.log('Platform received message:', message);
|
|
922
|
+
|
|
923
|
+
// Simulate platform processing and responding
|
|
924
|
+
setTimeout(() => {
|
|
925
|
+
console.log('Platform processing complete, sending response...');
|
|
926
|
+
this.simulatePlatformResponse(message, instance.idInstance);
|
|
927
|
+
}, 1000);
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
private async simulatePlatformResponse(originalMessage: SimplePlatformMessage, idInstance: number | bigint) {
|
|
931
|
+
const platformWebhook: SimplePlatformWebhook = {
|
|
932
|
+
messageId: `resp_${Date.now()}`,
|
|
933
|
+
from: originalMessage.to.replace('@c.us', ''),
|
|
934
|
+
text: `Thanks for your message: "${originalMessage.content}". This is an automated response.`,
|
|
935
|
+
timestamp: Date.now()
|
|
936
|
+
};
|
|
937
|
+
|
|
938
|
+
await this.handlePlatformWebhook(platformWebhook, idInstance);
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
```
|
|
942
|
+
|
|
943
|
+
### main.ts
|
|
944
|
+
|
|
945
|
+
```typescript
|
|
946
|
+
import express from "express";
|
|
947
|
+
import bodyParser from "body-parser";
|
|
948
|
+
import { formatPhoneNumber, GreenApiClient } from "@green-api/greenapi-integration";
|
|
949
|
+
import { SimpleTransformer } from "./simple-transformer";
|
|
950
|
+
import { SimpleStorage } from "./simple-storage";
|
|
951
|
+
import { SimpleAdapter } from "./simple-adapter";
|
|
952
|
+
import * as dotenv from "dotenv";
|
|
953
|
+
|
|
954
|
+
dotenv.config();
|
|
955
|
+
|
|
956
|
+
async function main() {
|
|
957
|
+
// Initialize components
|
|
958
|
+
const transformer = new SimpleTransformer();
|
|
959
|
+
const storage = new SimpleStorage();
|
|
960
|
+
const adapter = new SimpleAdapter(transformer, storage);
|
|
961
|
+
|
|
962
|
+
// Configuration for both instances
|
|
963
|
+
const visitorInstance = {
|
|
964
|
+
idInstance: Number(process.env.VISITOR_ID_INSTANCE),
|
|
965
|
+
apiTokenInstance: process.env.VISITOR_API_TOKEN!,
|
|
966
|
+
};
|
|
967
|
+
|
|
968
|
+
const agentInstance = {
|
|
969
|
+
idInstance: Number(process.env.AGENT_ID_INSTANCE),
|
|
970
|
+
apiTokenInstance: process.env.AGENT_API_TOKEN!,
|
|
971
|
+
};
|
|
972
|
+
console.log(visitorInstance, agentInstance);
|
|
973
|
+
|
|
974
|
+
// Create visitor's GREEN-API client (for sending initial message)
|
|
975
|
+
const visitorClient = new GreenApiClient(visitorInstance);
|
|
976
|
+
|
|
977
|
+
// Set up agent instance
|
|
978
|
+
console.log("Setting up agent instance...");
|
|
979
|
+
const user = await adapter.createUser("agent@example.com", {
|
|
980
|
+
email: "agent@example.com",
|
|
981
|
+
name: "Agent",
|
|
982
|
+
});
|
|
983
|
+
|
|
984
|
+
const instance = await adapter.createInstance({
|
|
985
|
+
idInstance: agentInstance.idInstance, apiTokenInstance: agentInstance.apiTokenInstance, settings: {
|
|
986
|
+
webhookUrl: process.env.WEBHOOK_URL + "/webhook/green-api",
|
|
987
|
+
webhookUrlToken: "your-secure-token",
|
|
988
|
+
incomingWebhook: "yes",
|
|
989
|
+
},
|
|
990
|
+
}, user.email);
|
|
991
|
+
|
|
992
|
+
console.log("Waiting 2 minutes for settings to apply...");
|
|
993
|
+
await new Promise(resolve => setTimeout(resolve, 120000));
|
|
994
|
+
console.log("Instance ready!");
|
|
995
|
+
|
|
996
|
+
// Set up webhook server
|
|
997
|
+
const app = express();
|
|
998
|
+
app.use(bodyParser.json());
|
|
999
|
+
|
|
1000
|
+
// Handle GREEN-API webhooks
|
|
1001
|
+
app.post("/webhook/green-api", async (req, res) => {
|
|
1002
|
+
try {
|
|
1003
|
+
console.log("Received webhook from GREEN-API:", req.body);
|
|
1004
|
+
await adapter.handleGreenApiWebhook(req.body, ["incomingMessageReceived"]);
|
|
1005
|
+
res.status(200).json({status: "ok"});
|
|
1006
|
+
} catch (error) {
|
|
1007
|
+
console.error("Error handling webhook:", error);
|
|
1008
|
+
res.status(500).json({error: "Internal server error"});
|
|
1009
|
+
}
|
|
1010
|
+
});
|
|
1011
|
+
|
|
1012
|
+
// Start the server
|
|
1013
|
+
const port = Number(process.env.PORT) || 3000;
|
|
1014
|
+
app.listen(port, () => {
|
|
1015
|
+
console.log(`Webhook server listening on port ${port}`);
|
|
1016
|
+
});
|
|
1017
|
+
|
|
1018
|
+
// Send initial message from visitor
|
|
1019
|
+
console.log("Sending initial message from visitor...");
|
|
1020
|
+
await visitorClient.sendMessage({
|
|
1021
|
+
chatId: formatPhoneNumber(process.env.AGENT_PHONE_NUMBER!),
|
|
1022
|
+
message: "Hello! This is a test message from a visitor.",
|
|
1023
|
+
type: "text",
|
|
1024
|
+
});
|
|
1025
|
+
|
|
1026
|
+
console.log("Initial message sent! Check the agent WhatsApp app to see the response.");
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
main().catch(console.error);
|
|
1030
|
+
```
|
|
1031
|
+
|
|
1032
|
+
### .env
|
|
1033
|
+
|
|
1034
|
+
```env
|
|
1035
|
+
VISITOR_ID_INSTANCE=your_visitor_instance_id
|
|
1036
|
+
VISITOR_API_TOKEN=your_visitor_instance_token
|
|
1037
|
+
AGENT_ID_INSTANCE=your_agent_instance_id
|
|
1038
|
+
AGENT_API_TOKEN=your_agent_instance_token
|
|
1039
|
+
AGENT_PHONE_NUMBER=your_agent_phone_number
|
|
1040
|
+
WEBHOOK_URL=your_webhook_url
|
|
1041
|
+
PORT=3000
|
|
1042
|
+
```
|
|
1043
|
+
|
|
1044
|
+
## Real-World Examples
|
|
1045
|
+
|
|
1046
|
+
For complete real-world integration examples, check out:
|
|
1047
|
+
|
|
1048
|
+
- [Rocket.Chat Integration](https://github.com/green-api/greenapi-integration-rocketchat)
|
|
1049
|
+
|
|
1050
|
+
## Utilities
|
|
1051
|
+
|
|
1052
|
+
The platform provides several utility functions:
|
|
1053
|
+
|
|
1054
|
+
```typescript
|
|
1055
|
+
// Format phone numbers for GREEN-API
|
|
1056
|
+
formatPhoneNumber('+1234567890') // Returns '1234567890@c.us'
|
|
1057
|
+
|
|
1058
|
+
// Generate secure random tokens
|
|
1059
|
+
generateRandomToken(32) // Returns a 32-character random token
|
|
1060
|
+
|
|
1061
|
+
// Extract phone number from vcard
|
|
1062
|
+
const vcard = 'BEGIN:VCARD\nTEL:+1234567890\nEND:VCARD'
|
|
1063
|
+
extractPhoneNumberFromVCard(vcard) // Returns '+1234567890'
|
|
1064
|
+
|
|
1065
|
+
// Validate settings values
|
|
1066
|
+
isValidSettingValue('webhookUrl', 'https://example.com') // Returns true
|
|
1067
|
+
|
|
1068
|
+
// Clean settings
|
|
1069
|
+
const input = {
|
|
1070
|
+
webhookUrl: 'https://example.com',
|
|
1071
|
+
outgoingWebhook: 'yes',
|
|
1072
|
+
invalidKey: 'value',
|
|
1073
|
+
delaySendMessagesMilliseconds: 'invalid'
|
|
1074
|
+
}
|
|
1075
|
+
validateAndCleanSettings(input) // Returns { webhookUrl: 'https://example.com', outgoingWebhook: 'yes' }
|
|
1076
|
+
```
|
|
1077
|
+
|
|
1078
|
+
## License
|
|
1079
|
+
|
|
1080
|
+
MIT
|