@green-api/greenapi-integration 0.5.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/README.md CHANGED
@@ -1,858 +1,1080 @@
1
- # Universal Integration Platform for GREEN-API
2
-
3
- ## Support links
4
-
5
- [![Support](https://img.shields.io/badge/support@green--api.com-D14836?style=for-the-badge&logo=gmail&logoColor=white)](mailto:support@greenapi.com)
6
- [![Support](https://img.shields.io/badge/Telegram-2CA5E0?style=for-the-badge&logo=telegram&logoColor=white)](https://t.me/greenapi_support_eng_bot)
7
- [![Support](https://img.shields.io/badge/WhatsApp-25D366?style=for-the-badge&logo=whatsapp&logoColor=white)](https://wa.me/77273122366)
8
-
9
- ## Guides & News
10
-
11
- [![Guides](https://img.shields.io/badge/YouTube-%23FF0000.svg?style=for-the-badge&logo=YouTube&logoColor=white)](https://www.youtube.com/@greenapi-en)
12
- [![News](https://img.shields.io/badge/Telegram-2CA5E0?style=for-the-badge&logo=telegram&logoColor=white)](https://t.me/green_api)
13
- [![News](https://img.shields.io/badge/WhatsApp-25D366?style=for-the-badge&logo=whatsapp&logoColor=white)](https://whatsapp.com/channel/0029VaLj6J4LNSa2B5Jx6s3h)
14
-
15
- - [Документация на русском языке](./README.ru.md)
16
-
17
- A flexible integration platform designed to simplify the process of connecting GREEN-API's WhatsApp gateway with various
18
- third-party services.
19
-
20
- ## Table of Contents
21
-
22
- - [Installation](#installation)
23
- - [Core Components](#core-components)
24
- - [Developer Guide](#developer-guide)
25
- - [Working Example](#working-example)
26
- - [Real-World Examples](#real-world-examples)
27
- - [Best Practices](#best-practices)
28
-
29
- ## Installation
30
-
31
- ```bash
32
- npm install @green-api/greenapi-integration
33
- ```
34
-
35
- ## Core Components
36
-
37
- ### 1. BaseAdapter
38
-
39
- The foundation of your integration. Handles message & instance management, and platform-specific logic.
40
-
41
- ```typescript
42
- abstract class BaseAdapter<TPlatformWebhook, TPlatformMessage> {
43
- public constructor(
44
- transformer: MessageTransformer<TPlatformWebhook, TPlatformMessage>,
45
- storage: StorageProvider
46
- );
47
-
48
- public abstract createPlatformClient(params: any): Promise<any>;
49
-
50
- public abstract sendToPlatform(message: TPlatformMessage, instance: TInstance): Promise<void>;
51
- }
52
- ```
53
-
54
- #### Methods
55
-
56
- When extending BaseAdapter, your implementation has access to several methods:
57
-
58
- ##### Webhook Handling
59
-
60
- These webhook handling methods call your message transformation methods automatically, without the need to use them
61
- directly in
62
- your code.
63
-
64
- ```typescript
65
- // Handle webhooks from your platform
66
- await adapter.handlePlatformWebhook(webhookData, instanceId);
67
-
68
- // Handle webhooks from GREEN-API. The second parameter is telling the function to handle only specific webhooks.
69
- // The second parameter must be specified, otherwise webhooks will not be processed.
70
- await adapter.handleGreenApiWebhook(webhook, ['incomingMessageReceived']);
71
- ```
72
-
73
- ##### Instance Management
74
-
75
- ```typescript
76
- // Create new instance
77
- const instance = await adapter.createInstance(instanceData, settings, userEmail);
78
-
79
- // Get instance details
80
- const details = await adapter.getInstance(instanceId);
81
-
82
- // Remove instance
83
- await adapter.removeInstance(instanceId);
84
- ```
85
-
86
- ##### User Management
87
-
88
- ```typescript
89
- // Create new user
90
- const user = await adapter.createUser(userEmail, userData);
91
-
92
- // Update user
93
- await adapter.updateUser(userEmail, updateData);
94
- ```
95
-
96
- #### Webhook Implementation Example
97
-
98
- ```typescript
99
- // Platform webhook endpoint
100
- app.post('/webhook/platform', async (req, res) => {
101
- try {
102
- await adapter.handlePlatformWebhook(req.body, instanceId);
103
- res.status(200).send();
104
- } catch (error) {
105
- console.error('Failed to handle platform webhook:', error);
106
- res.status(500).send();
107
- }
108
- });
109
-
110
- // GREEN-API webhook endpoint
111
- app.post('/webhook/green-api', async (req, res) => {
112
- try {
113
- // Process specific webhook types
114
- await adapter.handleGreenApiWebhook(req.body, [
115
- 'incomingMessageReceived',
116
- 'outgoingMessageStatus'
117
- ]);
118
- res.status(200).send();
119
- } catch (error) {
120
- console.error('Failed to handle GREEN-API webhook:', error);
121
- res.status(500).send();
122
- }
123
- });
124
- ```
125
-
126
- ### 2. MessageTransformer
127
-
128
- Handles message format conversion between GREEN-API and your platform.
129
-
130
- ```typescript
131
- abstract class MessageTransformer<TPlatformWebhook, TPlatformMessage> {
132
- abstract toPlatformMessage(webhook: GreenApiWebhook): TPlatformMessage;
133
-
134
- abstract toGreenApiMessage(message: TPlatformWebhook): Message;
135
- }
136
- ```
137
-
138
- ### 3. StorageProvider
139
-
140
- Interface for data persistence operations.
141
-
142
- ```typescript
143
- abstract class StorageProvider<TUser extends BaseUser = BaseUser, TInstance extends BaseInstance = Instance> {
144
- abstract createInstance(instance: BaseInstance, userId: bigint | number): Promise<TInstance>;
145
-
146
- abstract getInstance(idInstance: number | bigint): Promise<TInstance | null>;
147
-
148
- abstract removeInstance(instanceId: number | bigint): Promise<TInstance>;
149
-
150
- abstract createUser(data: any): Promise<TUser>;
151
-
152
- abstract findUser(identifier: string): Promise<TUser | null>;
153
-
154
- abstract updateUser(identifier: string, data: any): Promise<TUser>;
155
- }
156
- ```
157
-
158
- ### 4. BaseGreenApiAuthGuard
159
-
160
- Handles webhook authentication for incoming GREEN-API requests.
161
-
162
- ```typescript
163
- abstract class BaseGreenApiAuthGuard<T extends BaseRequest = BaseRequest> {
164
- constructor(protected storage: StorageProvider);
165
-
166
- // Validates incoming webhook requests
167
- async validateRequest(request: T): Promise<boolean>;
168
- }
169
- ```
170
-
171
- Example implementation of `BaseGreenApiAuthGuard`:
172
-
173
- ```typescript
174
- class YourAuthGuard extends BaseGreenApiAuthGuard<YourRequest> {
175
- constructor(storage: StorageProvider) {
176
- super(storage);
177
- }
178
- }
179
-
180
- // Using with Express
181
- app.post('/webhook', async (req, res) => {
182
- const guard = new YourAuthGuard(storage);
183
- try {
184
- await guard.validateRequest(req);
185
- // Process webhook
186
- } catch (error) {
187
- if (error instanceof AuthenticationError) {
188
- res.status(401).json({error: error.message});
189
- return;
190
- }
191
- res.status(500).json({error: 'Internal server error'});
192
- }
193
- });
194
- ```
195
-
196
- ### 5. GreenApiClient
197
-
198
- Direct interface to GREEN-API methods.
199
-
200
- ```typescript
201
- const client = new GreenApiClient({
202
- idInstance: 'your_instance_id',
203
- apiTokenInstance: 'your_token'
204
- });
205
-
206
- // Examples:
207
- await client.setProfilePicture(fileBlob);
208
- await client.getAuthorizationCode(phoneNumber);
209
- await client.getQR();
210
- ```
211
-
212
- ## Developer Guide
213
-
214
- This guide will walk you through creating your first integration with GREEN-API's WhatsApp gateway.
215
-
216
- ### Project Structure
217
-
218
- ```
219
- your-integration/
220
- ├── src/
221
- │ ├── core/
222
- │ │ ├── adapter.ts # Your platform adapter
223
- │ │ ├── transformer.ts # Message transformer
224
- │ │ ├── storage.ts # Data storage implementation
225
- │ │ └── router.ts # Webhook endpoints
226
- │ ├── types/
227
- │ │ └── types.ts # Platform-specific types
228
- │ └── main.ts # Main exports
229
- ├── package.json
230
- └── tsconfig.json
231
- ```
232
-
233
- ```mermaid
234
- graph TB
235
- subgraph "WhatsApp to Platform"
236
- WA[WhatsApp] -->|Send message| GA1[GREEN-API]
237
- GA1 -->|Webhook| INT1[Your Integration]
238
- INT1 -->|1 . Validate webhook| GD1[BaseGreenApiAuthGuard]
239
- INT1 -->|2 . Transform message| TR1[MessageTransformer]
240
- INT1 -->|3 . Send to platform| PL1[Your Platform]
241
- end
242
-
243
- subgraph "Platform to WhatsApp"
244
- PL2[Your Platform] -->|Webhook| INT2[Your Integration]
245
- INT2 -->|1 . Transform message| TR2[MessageTransformer]
246
- INT2 -->|2 . Send via API| GA2[GREEN-API]
247
- GA2 -->|Send message| WA2[WhatsApp]
248
- end
249
-
250
- subgraph "Components"
251
- style Components fill: #f9f9f9, stroke: #333, stroke-width: 2px
252
- TR[MessageTransformer]
253
- ST[StorageProvider]
254
- AD[BaseAdapter]
255
- GD[WebhookGuard]
256
- end
257
- ```
258
-
259
- ### Implementation Steps
260
-
261
- #### Step 1: Define Platform Types
262
-
263
- First, define the message types for your platform:
264
-
265
- ```typescript
266
- // types/types.ts
267
- export interface YourPlatformWebhook {
268
- id: string;
269
- from: string;
270
- message: string;
271
- timestamp: number;
272
- // Add other platform-specific fields
273
- }
274
-
275
- export interface YourPlatformMessage {
276
- recipient: string;
277
- content: string;
278
- // Add other platform-specific fields
279
- }
280
- ```
281
-
282
- #### Step 2: Create Message Transformer
283
-
284
- Create a transformer that converts messages between your platform's format and GREEN-API's format:
285
-
286
- ```typescript
287
- // core/transformer.ts
288
- import { MessageTransformer, Message, GreenApiWebhook } from '@green-api/greenapi-integration';
289
- import { YourPlatformWebhook, YourPlatformMessage } from '../types/types';
290
-
291
- export class YourTransformer extends MessageTransformer<YourPlatformWebhook, YourPlatformMessage> {
292
- toPlatformMessage(webhook: GreenApiWebhook): YourPlatformMessage {
293
- // Transform GREEN-API webhook to your platform format
294
- return {
295
- recipient: webhook.senderData.sender,
296
- content: webhook.messageData.textMessageData?.textMessage || '',
297
- };
298
- }
299
-
300
- toGreenApiMessage(message: YourPlatformWebhook): Message {
301
- // Transform your platform webhook to GREEN-API format
302
- return {
303
- type: 'text',
304
- chatId: message.from,
305
- message: message.message,
306
- };
307
- }
308
- }
309
- ```
310
-
311
- #### Step 3: Implement Storage Provider
312
-
313
- Create a storage provider to manage users and instances. You can use any database or ORM:
314
-
315
- ```typescript
316
- // core/storage.ts
317
- import { StorageProvider, BaseUser, Instance, Settings } from '@green-api/greenapi-integration';
318
- import { PrismaClient } from '@prisma/client'; // Or your database client
319
-
320
- export class YourStorage extends StorageProvider {
321
- private db: PrismaClient;
322
-
323
- constructor() {
324
- this.db = new PrismaClient();
325
- }
326
-
327
- async createInstance(instance: Instance, userId: bigint) {
328
- return this.db.instance.create({
329
- data: {
330
- idInstance: instance.idInstance,
331
- apiTokenInstance: instance.apiTokenInstance,
332
- userId,
333
- settings: instance.settings || {},
334
- },
335
- });
336
- }
337
-
338
- // Implement other required methods
339
- }
340
- ```
341
-
342
- #### Step 4: Create Your Platform Adapter
343
-
344
- The adapter handles the actual communication between platforms:
345
-
346
- ```typescript
347
- // core/adapter.ts
348
- import { BaseAdapter, BaseInstance } from '@green-api/greenapi-integration';
349
- import { YourPlatformClient } from 'your-platform-sdk';
350
- import { YourPlatformWebhook, YourPlatformMessage } from '../types/types';
351
-
352
- export class YourAdapter extends BaseAdapter<YourPlatformWebhook, YourPlatformMessage> {
353
- async createPlatformClient(config: { apiKey: string, apiUrl: string }) {
354
- return new YourPlatformClient({
355
- baseUrl: config.apiUrl,
356
- apiKey: config.apiKey,
357
- });
358
- }
359
-
360
- async sendToPlatform(message: YourPlatformMessage, instance: Instance) {
361
- const client = await this.createPlatformClient(instance.config);
362
- await client.sendMessage(message);
363
- }
364
- }
365
- ```
366
-
367
- #### Step 5: Implement Webhook Controller
368
-
369
- Define webhook endpoints that your application will listen to:
370
-
371
- ```typescript
372
- // core/webhook.ts
373
- import express from 'express';
374
- import { YourAdapter } from '../core/adapter';
375
- import { YourTransformer } from '../core/transformer';
376
- import { YourStorage } from '../core/storage';
377
-
378
- const router = express.Router();
379
- const storage = new YourStorage();
380
- const transformer = new YourTransformer();
381
- const adapter = new YourAdapter(transformer, storage);
382
-
383
- class WebhookGuard extends BaseGreenApiAuthGuard {
384
- constructor(storage: StorageProvider) {
385
- super(storage);
386
- }
387
- }
388
-
389
- const guard = new WebhookGuard(storage);
390
-
391
- // Webhook endpoints
392
- router.post('/green-api', async (req, res) => {
393
- try {
394
- // Validate webhook first
395
- await guard.validateRequest(req);
396
-
397
- // Process webhook if validation passed
398
- // As the second parameter, specfify the types of webhooks to be processed (otherwise skipped)
399
- await adapter.handleGreenApiWebhook(req.body, ['incomingMessageReceived']);
400
- res.status(200).json({status: 'ok'});
401
- } catch (error) {
402
- if (error instanceof AuthenticationError) {
403
- res.status(401).json({error: error.message});
404
- return;
405
- }
406
- console.error('Webhook error:', error);
407
- res.status(500).json({error: 'Internal server error'});
408
- }
409
- });
410
-
411
- router.post('/platform', async (req, res) => {
412
- try {
413
- const instanceId = req.query.instanceId;
414
- await adapter.handlePlatformWebhook(req.body, instanceId);
415
- res.status(200).json({status: 'ok'});
416
- } catch (error) {
417
- console.error('Platform webhook error:', error);
418
- res.status(500).json({error: 'Internal server error'});
419
- }
420
- });
421
-
422
- router.post('/instance', async (req, res) => {
423
- try {
424
- const {idInstance, apiTokenInstance, userEmail} = req.body;
425
-
426
- if (!idInstance || !apiTokenInstance || !userEmail) {
427
- throw new BadRequestError('Required fields missing');
428
- }
429
-
430
- const instance = await adapter.createInstance({
431
- idInstance: Number(idInstance),
432
- apiTokenInstance,
433
- settings: {
434
- webhookUrl: `${process.env.APP_URL}/webhook/green-api`,
435
- webhookUrlToken: `token_${Date.now()}`,
436
- incomingWebhook: 'yes'
437
- }
438
- }, userEmail);
439
-
440
- res.status(200).json({
441
- status: 'ok',
442
- data: instance,
443
- message: 'Instance created successfully. Please wait 2 minutes for settings to apply.'
444
- });
445
-
446
- } catch (error) {
447
- console.error('Instance creation error:', error);
448
- res.status(500).json({error: 'Failed to create instance'});
449
- }
450
- });
451
-
452
- export default router;
453
- ```
454
-
455
- #### Step 6: Create Application Entry Point
456
-
457
- Put it all together in your entrypoint:
458
-
459
- ```typescript
460
- // main.ts
461
- import express from 'express';
462
- import bodyParser from 'body-parser';
463
- import dotenv from 'dotenv';
464
- import webhookRouter from './controllers/webhook';
465
- import { YourAdapter } from './core/adapter';
466
- import { YourTransformer } from './core/transformer';
467
- import { YourStorage } from './core/storage';
468
-
469
- // Load environment variables
470
- dotenv.config();
471
-
472
- async function bootstrap() {
473
- // Initialize components
474
- const storage = new YourStorage();
475
- const transformer = new YourTransformer();
476
- const adapter = new YourAdapter(transformer, storage);
477
-
478
- // Create Express application
479
- const app = express();
480
- app.use(bodyParser.json());
481
-
482
- // Set up webhook routes
483
- app.use('/webhook', webhookRouter);
484
-
485
- // Start server
486
- const port = process.env.PORT || 3000;
487
- app.listen(port, () => {
488
- console.log(`Server running on port ${port}`);
489
- });
490
-
491
- console.log('Integration platform ready!');
492
- }
493
-
494
- // Handle errors
495
- bootstrap();
496
- ```
497
-
498
- ### Publishing Your Integration
499
-
500
- 1. **Prepare package.json**
501
-
502
- ```json
503
- {
504
- "name": "greenapi-integration-yourplatform",
505
- "version": "1.0.0",
506
- "main": "dist/index.js",
507
- "types": "dist/index.d.ts",
508
- "scripts": {
509
- "build": "tsc",
510
- "prepublishOnly": "npm run build"
511
- },
512
- "dependencies": {
513
- "@green-api/greenapi-integration": "^0.4.0",
514
- "express": "^4.18.2"
515
- // other dependencies
516
- }
517
- }
518
- ```
519
-
520
- 2. **Build and Publish**
521
-
522
- ```bash
523
- npm run build
524
- npm publish
525
- ```
526
-
527
- ## Working Example
528
-
529
- Check out the `/examples/custom-adapter` directory for a complete working example showing:
530
-
531
- - Two-way message flow between WhatsApp and a custom platform
532
- - Webhook handling
533
- - Instance setup and configuration
534
- - Message transformation
535
- - Error handling
536
-
537
- ### Running the Example
538
-
539
- 1. Clone the repository
540
- 2. Update .env with your GREEN-API credentials:
541
-
542
- ```env
543
- VISITOR_ID_INSTANCE=your_visitor_instance_id
544
- VISITOR_API_TOKEN=your_visitor_instance_token
545
- AGENT_ID_INSTANCE=your_agent_instance_id
546
- AGENT_API_TOKEN=your_agent_instance_token
547
- AGENT_PHONE_NUMBER=your_agent_phone_number
548
- WEBHOOK_URL=your_webhook_url
549
- PORT=3000
550
- ```
551
-
552
- 3. Install dependencies and run:
553
-
554
- ```bash
555
- cd examples/custom-adapter
556
- npm install
557
- npm start
558
- ```
559
-
560
- ## Complete Example Implementation
561
-
562
- ### Project Structure
563
-
564
- ```
565
- examples/
566
- └── custom-adapter/
567
- ├── src/
568
- │ ├── main.ts
569
- │ ├── simple-adapter.ts
570
- │ ├── simple-transformer.ts
571
- │ ├── simple-storage.ts
572
- │ └── types.ts
573
- ├── .env
574
- └── package.json
575
- ```
576
-
577
- ### types.ts
578
-
579
- ```typescript
580
- interface SimplePlatformWebhook {
581
- messageId: string;
582
- from: string;
583
- text: string;
584
- timestamp: number;
585
- }
586
-
587
- interface SimplePlatformMessage {
588
- to: string;
589
- content: string;
590
- replyTo?: string;
591
- }
592
- ```
593
-
594
- ### simple-transformer.ts
595
-
596
- ```typescript
597
- import {
598
- MessageTransformer,
599
- Message,
600
- GreenApiWebhook,
601
- formatPhoneNumber,
602
- IntegrationError,
603
- } from "@green-api/greenapi-integration";
604
- import { SimplePlatformMessage, SimplePlatformWebhook } from "./types";
605
-
606
- export class SimpleTransformer extends MessageTransformer<SimplePlatformWebhook, SimplePlatformMessage> {
607
- toPlatformMessage(webhook: GreenApiWebhook): SimplePlatformMessage {
608
- if (webhook.typeWebhook === "incomingMessageReceived") {
609
- if (webhook.messageData.typeMessage !== "extendedTextMessage") {
610
- throw new IntegrationError("Only text messages are supported", "BAD_REQUEST_ERROR", 400);
611
- }
612
-
613
- return {
614
- to: webhook.senderData.sender,
615
- content: webhook.messageData.extendedTextMessageData?.text || "",
616
- };
617
- }
618
- throw new IntegrationError("Only incomingMessageReceived type webhooks are supported", "INTEGRATION_ERROR", 500);
619
- }
620
-
621
- toGreenApiMessage(message: SimplePlatformWebhook): Message {
622
- return {
623
- type: "text",
624
- chatId: formatPhoneNumber(message.from),
625
- message: message.text,
626
- };
627
- }
628
- }
629
- ```
630
-
631
- ### simple-storage.ts
632
-
633
- ```typescript
634
- import { StorageProvider, BaseUser, Instance } from '@green-api/greenapi-integration';
635
-
636
- export class SimpleStorage extends StorageProvider {
637
- private users: Map<string, BaseUser> = new Map();
638
- private instances: Map<number, Instance> = new Map();
639
-
640
- async createInstance(instance: Instance, userId: bigint): Promise<Instance> {
641
- this.instances.set(Number(instance.idInstance), {
642
- ...instance,
643
- });
644
- return instance;
645
- }
646
-
647
- async getInstance(idInstance: number): Promise<Instance | null> {
648
- return this.instances.get(idInstance) || null;
649
- }
650
-
651
- async removeInstance(instanceId: number): Promise<Instance> {
652
- const instance = this.instances.get(instanceId);
653
- if (!instance) throw new Error('Instance not found');
654
- this.instances.delete(instanceId);
655
- return instance;
656
- }
657
-
658
- async createUser(data: any): Promise<BaseUser> {
659
- const user = {id: Date.now(), ...data};
660
- this.users.set(data.email, user);
661
- return user;
662
- }
663
-
664
- async findUser(identifier: string): Promise<BaseUser | null> {
665
- return this.users.get(identifier) || null;
666
- }
667
-
668
- async updateUser(identifier: string, data: any): Promise<BaseUser> {
669
- const user = await this.findUser(identifier);
670
- if (!user) throw new Error('User not found');
671
- const updated = {...user, ...data};
672
- this.users.set(identifier, updated);
673
- return updated;
674
- }
675
- }
676
- ```
677
-
678
- ### simple-adapter.ts
679
-
680
- ```typescript
681
- import { BaseAdapter, Instance } from "@green-api/greenapi-integration";
682
- import { SimplePlatformMessage, SimplePlatformWebhook } from "./types";
683
- import axios from 'axios';
684
-
685
- export class SimpleAdapter extends BaseAdapter<SimplePlatformWebhook, SimplePlatformMessage> {
686
- async createPlatformClient(config: { apiKey: string, apiUrl: string }) {
687
- return axios.create({
688
- baseURL: config.apiUrl,
689
- headers: {
690
- 'Authorization': `Bearer ${config.apiKey}`,
691
- 'Content-Type': 'application/json'
692
- }
693
- });
694
- }
695
-
696
- async sendToPlatform(message: SimplePlatformMessage, instance: Instance): Promise<void> {
697
- // In a real implementation, we would send to the platform
698
- // For demo, we'll just log and simulate a response
699
- console.log('Platform received message:', message);
700
-
701
- // Simulate platform processing and responding
702
- setTimeout(() => {
703
- console.log('Platform processing complete, sending response...');
704
- this.simulatePlatformResponse(message, instance.idInstance);
705
- }, 1000);
706
- }
707
-
708
- private async simulatePlatformResponse(originalMessage: SimplePlatformMessage, idInstance: number | bigint) {
709
- const platformWebhook: SimplePlatformWebhook = {
710
- messageId: `resp_${Date.now()}`,
711
- from: originalMessage.to.replace('@c.us', ''),
712
- text: `Thanks for your message: "${originalMessage.content}". This is an automated response.`,
713
- timestamp: Date.now()
714
- };
715
-
716
- await this.handlePlatformWebhook(platformWebhook, idInstance);
717
- }
718
- }
719
- ```
720
-
721
- ### main.ts
722
-
723
- ```typescript
724
- import express from "express";
725
- import bodyParser from "body-parser";
726
- import { formatPhoneNumber, GreenApiClient } from "@green-api/greenapi-integration";
727
- import { SimpleTransformer } from "./simple-transformer";
728
- import { SimpleStorage } from "./simple-storage";
729
- import { SimpleAdapter } from "./simple-adapter";
730
- import * as dotenv from "dotenv";
731
-
732
- dotenv.config();
733
-
734
- async function main() {
735
- // Initialize components
736
- const transformer = new SimpleTransformer();
737
- const storage = new SimpleStorage();
738
- const adapter = new SimpleAdapter(transformer, storage);
739
-
740
- // Configuration for both instances
741
- const visitorInstance = {
742
- idInstance: Number(process.env.VISITOR_ID_INSTANCE),
743
- apiTokenInstance: process.env.VISITOR_API_TOKEN!,
744
- };
745
-
746
- const agentInstance = {
747
- idInstance: Number(process.env.AGENT_ID_INSTANCE),
748
- apiTokenInstance: process.env.AGENT_API_TOKEN!,
749
- };
750
- console.log(visitorInstance, agentInstance);
751
-
752
- // Create visitor's GREEN-API client (for sending initial message)
753
- const visitorClient = new GreenApiClient(visitorInstance);
754
-
755
- // Set up agent instance
756
- console.log("Setting up agent instance...");
757
- const user = await adapter.createUser("agent@example.com", {
758
- email: "agent@example.com",
759
- name: "Agent",
760
- });
761
-
762
- const instance = await adapter.createInstance({
763
- idInstance: agentInstance.idInstance, apiTokenInstance: agentInstance.apiTokenInstance, settings: {
764
- webhookUrl: process.env.WEBHOOK_URL + "/webhook/green-api",
765
- webhookUrlToken: "your-secure-token",
766
- incomingWebhook: "yes",
767
- },
768
- }, user.email);
769
-
770
- console.log("Waiting 2 minutes for settings to apply...");
771
- await new Promise(resolve => setTimeout(resolve, 120000));
772
- console.log("Instance ready!");
773
-
774
- // Set up webhook server
775
- const app = express();
776
- app.use(bodyParser.json());
777
-
778
- // Handle GREEN-API webhooks
779
- app.post("/webhook/green-api", async (req, res) => {
780
- try {
781
- console.log("Received webhook from GREEN-API:", req.body);
782
- await adapter.handleGreenApiWebhook(req.body, ["incomingMessageReceived"]);
783
- res.status(200).json({status: "ok"});
784
- } catch (error) {
785
- console.error("Error handling webhook:", error);
786
- res.status(500).json({error: "Internal server error"});
787
- }
788
- });
789
-
790
- // Start the server
791
- const port = Number(process.env.PORT) || 3000;
792
- app.listen(port, () => {
793
- console.log(`Webhook server listening on port ${port}`);
794
- });
795
-
796
- // Send initial message from visitor
797
- console.log("Sending initial message from visitor...");
798
- await visitorClient.sendMessage({
799
- chatId: formatPhoneNumber(process.env.AGENT_PHONE_NUMBER!),
800
- message: "Hello! This is a test message from a visitor.",
801
- type: "text",
802
- });
803
-
804
- console.log("Initial message sent! Check the agent WhatsApp app to see the response.");
805
- }
806
-
807
- main().catch(console.error);
808
- ```
809
-
810
- ### .env
811
-
812
- ```env
813
- VISITOR_ID_INSTANCE=your_visitor_instance_id
814
- VISITOR_API_TOKEN=your_visitor_instance_token
815
- AGENT_ID_INSTANCE=your_agent_instance_id
816
- AGENT_API_TOKEN=your_agent_instance_token
817
- AGENT_PHONE_NUMBER=your_agent_phone_number
818
- WEBHOOK_URL=your_webhook_url
819
- PORT=3000
820
- ```
821
-
822
- ## Real-World Examples
823
-
824
- For complete real-world integration examples, check out:
825
-
826
- - [Rocket.Chat Integration](https://github.com/green-api/greenapi-integration-rocketchat)
827
-
828
- ## Utilities
829
-
830
- The platform provides several utility functions:
831
-
832
- ```typescript
833
- // Format phone numbers for GREEN-API
834
- formatPhoneNumber('+1234567890') // Returns '1234567890@c.us'
835
-
836
- // Generate secure random tokens
837
- generateRandomToken(32) // Returns a 32-character random token
838
-
839
- // Extract phone number from vcard
840
- const vcard = 'BEGIN:VCARD\nTEL:+1234567890\nEND:VCARD'
841
- extractPhoneNumberFromVCard(vcard) // Returns '+1234567890'
842
-
843
- // Validate settings values
844
- isValidSettingValue('webhookUrl', 'https://example.com') // Returns true
845
-
846
- // Clean settings
847
- const input = {
848
- webhookUrl: 'https://example.com',
849
- outgoingWebhook: 'yes',
850
- invalidKey: 'value',
851
- delaySendMessagesMilliseconds: 'invalid'
852
- }
853
- validateAndCleanSettings(input) // Returns { webhookUrl: 'https://example.com', outgoingWebhook: 'yes' }
854
- ```
855
-
856
- ## License
857
-
858
- MIT
1
+ # Universal Integration Platform for GREEN-API
2
+
3
+ ## Support links
4
+
5
+ [![Support](https://img.shields.io/badge/support@green--api.com-D14836?style=for-the-badge&logo=gmail&logoColor=white)](mailto:support@greenapi.com)
6
+ [![Support](https://img.shields.io/badge/Telegram-2CA5E0?style=for-the-badge&logo=telegram&logoColor=white)](https://t.me/greenapi_support_eng_bot)
7
+ [![Support](https://img.shields.io/badge/WhatsApp-25D366?style=for-the-badge&logo=whatsapp&logoColor=white)](https://wa.me/77273122366)
8
+
9
+ ## Guides & News
10
+
11
+ [![Guides](https://img.shields.io/badge/YouTube-%23FF0000.svg?style=for-the-badge&logo=YouTube&logoColor=white)](https://www.youtube.com/@greenapi-en)
12
+ [![News](https://img.shields.io/badge/Telegram-2CA5E0?style=for-the-badge&logo=telegram&logoColor=white)](https://t.me/green_api)
13
+ [![News](https://img.shields.io/badge/WhatsApp-25D366?style=for-the-badge&logo=whatsapp&logoColor=white)](https://whatsapp.com/channel/0029VaLj6J4LNSa2B5Jx6s3h)
14
+
15
+ [![NPM Version](https://img.shields.io/npm/v/@green-api/greenapi-integration)](https://www.npmjs.com/package/@green-api/whatsapp-chatbot-js-v2)
16
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](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