@green-api/greenapi-integration 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,771 @@
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
+ The `BaseAdapter` internally uses `GreenApiClient` for all common operations, so in most cases, you don't need to use
41
+ GreenApiClient methods directly.
42
+
43
+ **When to use `BaseAdapter` vs `GreenApiClient`**:
44
+
45
+ ✅ Use `BaseAdapter` methods for all standard operations (sending messages, handling webhooks, managing instances)
46
+
47
+ ⚠️ Use `GreenApiClient` directly only for specialized operations not covered by BaseAdapter (like setProfilePicture,
48
+ getAuthorizationCode)
49
+
50
+ ```typescript
51
+ abstract class BaseAdapter<TPlatformWebhook, TPlatformMessage> {
52
+ public constructor(
53
+ transformer: MessageTransformer<TPlatformWebhook, TPlatformMessage>,
54
+ storage: StorageProvider
55
+ );
56
+
57
+ public abstract createPlatformClient(params: any): Promise<any>;
58
+
59
+ public abstract sendToPlatform(message: TPlatformMessage, instance: TInstance): Promise<void>;
60
+ }
61
+ ```
62
+
63
+ **Example of proper usage:**
64
+
65
+ ```typescript
66
+ // ✅ CORRECT: Using BaseAdapter for standard operations
67
+ const adapter = new YourAdapter(transformer, storage);
68
+ await adapter.handlePlatformWebhook(webhook, instanceId);
69
+ await adapter.createInstance(instance, settings, userCred);
70
+ await adapter.sendMessage(transformedWebhook);
71
+
72
+ // ⚠️ ONLY IF NEEDED: Direct GreenApiClient usage for specialized operations
73
+ const client = new GreenApiClient(instance);
74
+ await client.setProfilePicture(fileBlob);
75
+ await client.getAuthorizationCode(phoneNumber);
76
+ ```
77
+
78
+ ### 2. MessageTransformer
79
+
80
+ Handles message format conversion between GREEN-API and your platform.
81
+
82
+ ```typescript
83
+ abstract class MessageTransformer<TPlatformWebhook, TPlatformMessage> {
84
+ abstract toPlatformMessage(webhook: IncomingGreenApiWebhook): TPlatformMessage;
85
+
86
+ abstract toGreenApiMessage(message: TPlatformWebhook): Message;
87
+ }
88
+ ```
89
+
90
+ ### 3. StorageProvider
91
+
92
+ Interface for data persistence operations.
93
+
94
+ ```typescript
95
+ abstract class StorageProvider<TUser extends BaseUser = BaseUser, TInstance extends BaseInstance = Instance> {
96
+ abstract createInstance(instance: BaseInstance, userId: bigint | number, settings?: Settings): Promise<TInstance>;
97
+
98
+ abstract getInstance(idInstance: number | bigint): Promise<TInstance | null>;
99
+
100
+ abstract removeInstance(instanceId: number | bigint): Promise<TInstance>;
101
+
102
+ abstract createUser(data: any): Promise<TUser>;
103
+
104
+ abstract findUser(identifier: string): Promise<TUser | null>;
105
+
106
+ abstract updateUser(identifier: string, data: any): Promise<TUser>;
107
+ }
108
+ ```
109
+
110
+ ### 4. BaseGreenApiAuthGuard
111
+
112
+ Handles webhook authentication for incoming GREEN-API requests.
113
+
114
+ ```typescript
115
+ abstract class BaseGreenApiAuthGuard<T extends BaseRequest = BaseRequest> {
116
+ constructor(protected storage: StorageProvider);
117
+
118
+ // Validates incoming webhook requests
119
+ async validateRequest(request: T): Promise<boolean>;
120
+ }
121
+ ```
122
+
123
+ Example implementation of `BaseGreenApiAuthGuard`:
124
+
125
+ ```typescript
126
+ class YourAuthGuard extends BaseGreenApiAuthGuard<YourRequest> {
127
+ constructor(storage: StorageProvider) {
128
+ super(storage);
129
+ }
130
+ }
131
+
132
+ // Using with Express
133
+ app.post('/webhook', async (req, res) => {
134
+ const guard = new YourAuthGuard(storage);
135
+ try {
136
+ await guard.validateRequest(req);
137
+ // Process webhook
138
+ } catch (error) {
139
+ if (error instanceof AuthenticationError) {
140
+ res.status(401).json({error: error.message});
141
+ return;
142
+ }
143
+ res.status(500).json({error: 'Internal server error'});
144
+ }
145
+ });
146
+ ```
147
+
148
+ ### 5. GreenApiClient
149
+
150
+ Direct interface to GREEN-API endpoints. While most operations should be handled through BaseAdapter, GreenApiClient can
151
+ be used directly for specialized operations.
152
+
153
+ ```typescript
154
+ const client = new GreenApiClient({
155
+ idInstance: 'your_instance_id',
156
+ apiTokenInstance: 'your_token'
157
+ });
158
+
159
+ // Examples of specialized operations:
160
+ await client.setProfilePicture(fileBlob);
161
+ await client.getAuthorizationCode(phoneNumber);
162
+ await client.getQR();
163
+ ```
164
+
165
+ ## Developer Guide
166
+
167
+ ### Project Structure
168
+
169
+ ```
170
+ your-integration/
171
+ ├── src/
172
+ │ ├── core/
173
+ │ │ ├── adapter.ts # Your platform adapter
174
+ │ │ ├── transformer.ts # Message transformer
175
+ │ │ ├── storage.ts # Data storage implementation
176
+ │ │ └── router.ts # Webhook endpoints
177
+ │ ├── types/
178
+ │ │ └── types.ts # Platform-specific types
179
+ │ └── main.ts # Main exports
180
+ ├── package.json
181
+ └── tsconfig.json
182
+ ```
183
+
184
+ ### Implementation Steps
185
+
186
+ 1. **Define Platform Types**
187
+
188
+ ```typescript
189
+ // types/types.ts
190
+ export interface YourPlatformWebhook {
191
+ id: string;
192
+ from: string;
193
+ message: string;
194
+ timestamp: number;
195
+ // Add other platform-specific fields
196
+ }
197
+
198
+ export interface YourPlatformMessage {
199
+ recipient: string;
200
+ content: string;
201
+ // Add other platform-specific fields
202
+ }
203
+ ```
204
+
205
+ 2. **Create Message Transformer**
206
+
207
+ ```typescript
208
+ // core/transformer.ts
209
+ import { MessageTransformer, Message, IncomingGreenApiWebhook } from '@green-api/greenapi-integration';
210
+ import { YourPlatformWebhook, YourPlatformMessage } from '../types/types';
211
+
212
+ export class YourTransformer extends MessageTransformer<YourPlatformWebhook, YourPlatformMessage> {
213
+ toPlatformMessage(webhook: IncomingGreenApiWebhook): YourPlatformMessage {
214
+ // Transform GREEN-API webhook to your platform format
215
+ return {
216
+ recipient: webhook.senderData.sender,
217
+ content: webhook.messageData.textMessageData?.textMessage || '',
218
+ };
219
+ }
220
+
221
+ toGreenApiMessage(message: YourPlatformWebhook): Message {
222
+ // Transform your platform webhook to GREEN-API format
223
+ return {
224
+ type: 'text',
225
+ chatId: message.from,
226
+ message: message.message,
227
+ };
228
+ }
229
+ }
230
+ ```
231
+
232
+ 3. **Implement Storage**
233
+
234
+ ```typescript
235
+ // core/storage.ts
236
+ import { StorageProvider, BaseUser, BaseInstance, Settings } from '@green-api/greenapi-integration';
237
+ import { PrismaClient } from '@prisma/client'; // Or your database client
238
+
239
+ export class YourStorage extends StorageProvider {
240
+ private db: PrismaClient;
241
+
242
+ constructor() {
243
+ this.db = new PrismaClient();
244
+ }
245
+
246
+ async createInstance(instance: BaseInstance, userId: bigint, settings?: Settings) {
247
+ return this.db.instance.create({
248
+ data: {
249
+ idInstance: instance.idInstance,
250
+ apiTokenInstance: instance.apiTokenInstance,
251
+ userId,
252
+ settings: settings || {},
253
+ },
254
+ });
255
+ }
256
+
257
+ // Implement other required methods
258
+ }
259
+ ```
260
+
261
+ 4. **Create Platform Adapter**
262
+
263
+ ```typescript
264
+ // core/adapter.ts
265
+ import { BaseAdapter, BaseInstance } from '@green-api/greenapi-integration';
266
+ import { YourPlatformClient } from 'your-platform-sdk';
267
+ import { YourPlatformWebhook, YourPlatformMessage } from '../types/types';
268
+
269
+ export class YourAdapter extends BaseAdapter<YourPlatformWebhook, YourPlatformMessage> {
270
+ async createPlatformClient(config: { apiKey: string, apiUrl: string }) {
271
+ return new YourPlatformClient({
272
+ baseUrl: config.apiUrl,
273
+ apiKey: config.apiKey,
274
+ });
275
+ }
276
+
277
+ async sendToPlatform(message: YourPlatformMessage, instance: BaseInstance) {
278
+ const client = await this.createPlatformClient(instance.config);
279
+ await client.sendMessage(message);
280
+ }
281
+ }
282
+ ```
283
+
284
+ 5. **Implement Webhook Controller**
285
+
286
+ ```typescript
287
+ // core/webhook.ts
288
+ import express from 'express';
289
+ import { YourAdapter } from '../core/adapter';
290
+ import { YourTransformer } from '../core/transformer';
291
+ import { YourStorage } from '../core/storage';
292
+
293
+ const router = express.Router();
294
+ const storage = new YourStorage();
295
+ const transformer = new YourTransformer();
296
+ const adapter = new YourAdapter(transformer, storage);
297
+
298
+ class WebhookGuard extends BaseGreenApiAuthGuard {
299
+ constructor(storage: StorageProvider) {
300
+ super(storage);
301
+ }
302
+ }
303
+
304
+ const guard = new WebhookGuard(storage);
305
+
306
+ // Webhook endpoints
307
+ router.post('/green-api', async (req, res) => {
308
+ try {
309
+ // Validate webhook first
310
+ await guard.validateRequest(req);
311
+
312
+ // Process webhook if validation passed
313
+ // As the second parameter, specfify the types of webhooks to be processed (otherwise skipped)
314
+ await adapter.handleGreenApiWebhook(req.body, ['incomingMessageReceived']);
315
+ res.status(200).json({status: 'ok'});
316
+ } catch (error) {
317
+ if (error instanceof AuthenticationError) {
318
+ res.status(401).json({error: error.message});
319
+ return;
320
+ }
321
+ console.error('Webhook error:', error);
322
+ res.status(500).json({error: 'Internal server error'});
323
+ }
324
+ });
325
+
326
+ router.post('/platform', async (req, res) => {
327
+ try {
328
+ const instanceId = req.query.instanceId;
329
+ await adapter.handlePlatformWebhook(req.body, instanceId);
330
+ res.status(200).json({status: 'ok'});
331
+ } catch (error) {
332
+ console.error('Platform webhook error:', error);
333
+ res.status(500).json({error: 'Internal server error'});
334
+ }
335
+ });
336
+
337
+ router.post('/instance', async (req, res) => {
338
+ try {
339
+ const {idInstance, apiTokenInstance, userEmail} = req.body;
340
+
341
+ if (!idInstance || !apiTokenInstance || !userEmail) {
342
+ throw new BadRequestError('Required fields missing');
343
+ }
344
+
345
+ const instance = await adapter.createInstance({
346
+ idInstance: Number(idInstance),
347
+ apiTokenInstance
348
+ }, {
349
+ webhookUrl: `${process.env.APP_URL}/webhook/green-api`,
350
+ webhookUrlToken: `token_${Date.now()}`, // In production, use a secure token generator
351
+ incomingWebhook: 'yes'
352
+ }, userEmail);
353
+
354
+ res.status(200).json({
355
+ status: 'ok',
356
+ data: instance,
357
+ message: 'Instance created successfully. Please wait 2 minutes for settings to apply.'
358
+ });
359
+
360
+ } catch (error) {
361
+ console.error('Instance creation error:', error);
362
+ res.status(500).json({error: 'Failed to create instance'});
363
+ }
364
+ });
365
+
366
+ export default router;
367
+ ```
368
+
369
+ 6. **Create Application Entry Point**
370
+
371
+ ```typescript
372
+ // main.ts
373
+ import express from 'express';
374
+ import bodyParser from 'body-parser';
375
+ import dotenv from 'dotenv';
376
+ import webhookRouter from './controllers/webhook';
377
+ import { YourAdapter } from './core/adapter';
378
+ import { YourTransformer } from './core/transformer';
379
+ import { YourStorage } from './core/storage';
380
+
381
+ // Load environment variables
382
+ dotenv.config();
383
+
384
+ async function bootstrap() {
385
+ // Initialize components
386
+ const storage = new YourStorage();
387
+ const transformer = new YourTransformer();
388
+ const adapter = new YourAdapter(transformer, storage);
389
+
390
+ // Create Express application
391
+ const app = express();
392
+ app.use(bodyParser.json());
393
+
394
+ // Set up webhook routes
395
+ app.use('/webhook', webhookRouter);
396
+
397
+ // Start server
398
+ const port = process.env.PORT || 3000;
399
+ app.listen(port, () => {
400
+ console.log(`Server running on port ${port}`);
401
+ });
402
+
403
+ console.log('Integration platform ready!');
404
+ }
405
+
406
+ // Handle errors
407
+ bootstrap();
408
+ ```
409
+
410
+ Or with NestJS:
411
+
412
+ ```typescript
413
+ // main.ts
414
+ import { NestFactory } from '@nestjs/core';
415
+ import { AppModule } from './app.module';
416
+ import helmet from 'helmet';
417
+
418
+ async function bootstrap() {
419
+ const app = await NestFactory.create(AppModule);
420
+ app.setGlobalPrefix('api');
421
+ app.use(helmet());
422
+ await app.listen(process.env.PORT ?? 3000);
423
+ }
424
+
425
+ bootstrap();
426
+ ```
427
+
428
+ ### Publishing Your Integration
429
+
430
+ 1. **Prepare package.json**
431
+
432
+ ```json
433
+ {
434
+ "name": "greenapi-integration-yourplatform",
435
+ "version": "1.0.0",
436
+ "main": "dist/index.js",
437
+ "types": "dist/index.d.ts",
438
+ "scripts": {
439
+ "build": "tsc",
440
+ "prepublishOnly": "npm run build"
441
+ },
442
+ "dependencies": {
443
+ "@green-api/greenapi-integration": "^1.0.0",
444
+ "@prisma/client": "^5.0.0",
445
+ "express": "^4.18.2"
446
+ // other dependencies
447
+ }
448
+ }
449
+ ```
450
+
451
+ 2. **Build and Publish**
452
+
453
+ ```bash
454
+ npm run build
455
+ npm publish
456
+ ```
457
+
458
+ ## Working Example
459
+
460
+ Check out the `/examples/custom-adapter` directory for a complete working example showing:
461
+
462
+ - Two-way message flow between WhatsApp and a custom platform
463
+ - Webhook handling
464
+ - Instance setup and configuration
465
+ - Message transformation
466
+ - Error handling
467
+
468
+ ### Running the Example
469
+
470
+ 1. Clone the repository
471
+ 2. Update .env with your GREEN-API credentials:
472
+
473
+ ```env
474
+ VISITOR_ID_INSTANCE=your_visitor_instance_id
475
+ VISITOR_API_TOKEN=your_visitor_instance_token
476
+ AGENT_ID_INSTANCE=your_agent_instance_id
477
+ AGENT_API_TOKEN=your_agent_instance_token
478
+ AGENT_PHONE_NUMBER=your_agent_phone_number
479
+ WEBHOOK_URL=your_webhook_url
480
+ PORT=3000
481
+ ```
482
+
483
+ 3. Install dependencies and run:
484
+
485
+ ```bash
486
+ cd examples/custom-adapter
487
+ npm install
488
+ npm start
489
+ ```
490
+
491
+ ## Complete Example Implementation
492
+
493
+ ### Project Structure
494
+
495
+ ```
496
+ examples/
497
+ └── custom-adapter/
498
+ ├── src/
499
+ │ ├── main.ts
500
+ │ ├── simple-adapter.ts
501
+ │ ├── simple-transformer.ts
502
+ │ ├── simple-storage.ts
503
+ │ └── types.ts
504
+ ├── .env
505
+ └── package.json
506
+ ```
507
+
508
+ ### types.ts
509
+
510
+ ```typescript
511
+ interface SimplePlatformWebhook {
512
+ messageId: string;
513
+ from: string;
514
+ text: string;
515
+ timestamp: number;
516
+ }
517
+
518
+ interface SimplePlatformMessage {
519
+ to: string;
520
+ content: string;
521
+ replyTo?: string;
522
+ }
523
+ ```
524
+
525
+ ### simple-transformer.ts
526
+
527
+ ```typescript
528
+ import { MessageTransformer, Message, IncomingGreenApiWebhook, formatPhoneNumber } from 'greenapi-integration';
529
+
530
+ export class SimpleTransformer extends MessageTransformer<SimplePlatformWebhook, SimplePlatformMessage> {
531
+ toPlatformMessage(webhook: IncomingGreenApiWebhook): SimplePlatformMessage {
532
+ if (webhook.messageData.typeMessage !== 'extendedTextMessage') {
533
+ throw new Error('Only text messages are supported');
534
+ }
535
+
536
+ return {
537
+ to: webhook.senderData.sender,
538
+ content: webhook.messageData.extendedTextMessageData?.text || '',
539
+ };
540
+ }
541
+
542
+ toGreenApiMessage(message: SimplePlatformWebhook): Message {
543
+ return {
544
+ type: 'text',
545
+ chatId: formatPhoneNumber(message.from),
546
+ message: message.text,
547
+ };
548
+ }
549
+ }
550
+ ```
551
+
552
+ ### simple-storage.ts
553
+
554
+ ```typescript
555
+ import { StorageProvider, BaseUser, BaseInstance, Settings } from 'greenapi-integration';
556
+
557
+ export class SimpleStorage extends StorageProvider {
558
+ private users: Map<string, BaseUser> = new Map();
559
+ private instances: Map<number, BaseInstance> = new Map();
560
+
561
+ async createInstance(instance: BaseInstance, userId: bigint, settings?: Settings): Promise<BaseInstance> {
562
+ this.instances.set(Number(instance.idInstance), {
563
+ ...instance,
564
+ settings: settings || {}
565
+ });
566
+ return instance;
567
+ }
568
+
569
+ async getInstance(idInstance: number): Promise<BaseInstance | null> {
570
+ return this.instances.get(idInstance) || null;
571
+ }
572
+
573
+ async removeInstance(instanceId: number): Promise<BaseInstance> {
574
+ const instance = this.instances.get(instanceId);
575
+ if (!instance) throw new Error('Instance not found');
576
+ this.instances.delete(instanceId);
577
+ return instance;
578
+ }
579
+
580
+ async createUser(data: any): Promise<BaseUser> {
581
+ const user = {id: Date.now(), ...data};
582
+ this.users.set(data.email, user);
583
+ return user;
584
+ }
585
+
586
+ async findUser(identifier: string): Promise<BaseUser | null> {
587
+ return this.users.get(identifier) || null;
588
+ }
589
+
590
+ async updateUser(identifier: string, data: any): Promise<BaseUser> {
591
+ const user = await this.findUser(identifier);
592
+ if (!user) throw new Error('User not found');
593
+ const updated = {...user, ...data};
594
+ this.users.set(identifier, updated);
595
+ return updated;
596
+ }
597
+ }
598
+ ```
599
+
600
+ ### simple-adapter.ts
601
+
602
+ ```typescript
603
+ import { BaseAdapter, BaseInstance } from "greenapi-integration";
604
+ import axios from 'axios';
605
+
606
+ export class SimpleAdapter extends BaseAdapter<SimplePlatformWebhook, SimplePlatformMessage> {
607
+ async createPlatformClient(config: { apiKey: string, apiUrl: string }) {
608
+ return axios.create({
609
+ baseURL: config.apiUrl,
610
+ headers: {
611
+ 'Authorization': `Bearer ${config.apiKey}`,
612
+ 'Content-Type': 'application/json'
613
+ }
614
+ });
615
+ }
616
+
617
+ async sendToPlatform(message: SimplePlatformMessage, instance: BaseInstance): Promise<void> {
618
+ // In a real implementation, we would send to the platform
619
+ // For demo, we'll just log and simulate a response
620
+ console.log('Platform received message:', message);
621
+
622
+ // Simulate platform processing and responding
623
+ setTimeout(() => {
624
+ console.log('Platform processing complete, sending response...');
625
+ this.simulatePlatformResponse(message, instance.idInstance);
626
+ }, 1000);
627
+ }
628
+
629
+ private async simulatePlatformResponse(originalMessage: SimplePlatformMessage, idInstance: number | bigint) {
630
+ const platformWebhook: SimplePlatformWebhook = {
631
+ messageId: `resp_${Date.now()}`,
632
+ from: originalMessage.to.replace('@c.us', ''),
633
+ text: `Thanks for your message: "${originalMessage.content}". This is an automated response.`,
634
+ timestamp: Date.now()
635
+ };
636
+
637
+ await this.handlePlatformWebhook(platformWebhook, idInstance);
638
+ }
639
+ }
640
+ ```
641
+
642
+ ### main.ts
643
+
644
+ ```typescript
645
+ import express from "express";
646
+ import bodyParser from "body-parser";
647
+ import { formatPhoneNumber, GreenApiClient } from "greenapi-integration";
648
+ import { SimpleTransformer } from "./simple-transformer";
649
+ import { SimpleStorage } from "./simple-storage";
650
+ import { SimpleAdapter } from "./simple-adapter";
651
+ import * as dotenv from "dotenv";
652
+
653
+ dotenv.config();
654
+
655
+ async function main() {
656
+ // Initialize components
657
+ const transformer = new SimpleTransformer();
658
+ const storage = new SimpleStorage();
659
+ const adapter = new SimpleAdapter(transformer, storage);
660
+
661
+ // Configuration for both instances
662
+ const visitorInstance = {
663
+ idInstance: Number(process.env.VISITOR_ID_INSTANCE),
664
+ apiTokenInstance: process.env.VISITOR_API_TOKEN!,
665
+ };
666
+
667
+ const agentInstance = {
668
+ idInstance: Number(process.env.AGENT_ID_INSTANCE),
669
+ apiTokenInstance: process.env.AGENT_API_TOKEN!,
670
+ };
671
+
672
+ // Create visitor's GREEN-API client (for sending initial message)
673
+ const visitorClient = new GreenApiClient(visitorInstance);
674
+
675
+ // Set up agent instance
676
+ console.log("Setting up agent instance...");
677
+ const user = await adapter.createUser("agent@example.com", {
678
+ email: "agent@example.com",
679
+ name: "Agent",
680
+ });
681
+
682
+ const instance = await adapter.createInstance(agentInstance, {
683
+ webhookUrl: process.env.WEBHOOK_URL + "/webhook/green-api",
684
+ webhookUrlToken: "your-secure-token",
685
+ incomingWebhook: "yes",
686
+ }, user.email);
687
+
688
+ console.log("Waiting 2 minutes for settings to apply...");
689
+ await new Promise(resolve => setTimeout(resolve, 120000));
690
+ console.log("Instance ready!");
691
+
692
+ // Set up webhook server
693
+ const app = express();
694
+ app.use(bodyParser.json());
695
+
696
+ // Handle GREEN-API webhooks
697
+ app.post("/webhook/green-api", async (req, res) => {
698
+ try {
699
+ console.log("Received webhook from GREEN-API:", req.body);
700
+ await adapter.handleGreenApiWebhook(req.body, ["incomingMessageReceived"]);
701
+ res.status(200).json({status: "ok"});
702
+ } catch (error) {
703
+ console.error("Error handling webhook:", error);
704
+ res.status(500).json({error: "Internal server error"});
705
+ }
706
+ });
707
+
708
+ // Start the server
709
+ const port = process.env.PORT || 3000;
710
+ app.listen(port, () => {
711
+ console.log(`Webhook server listening on port ${port}`);
712
+ });
713
+
714
+ // Send initial message from visitor
715
+ console.log("Sending initial message from visitor...");
716
+ await visitorClient.sendMessage({
717
+ chatId: formatPhoneNumber(process.env.AGENT_PHONE_NUMBER!),
718
+ message: "Hello! This is a test message from a visitor.",
719
+ type: "text",
720
+ });
721
+
722
+ console.log("Initial message sent! Check the agent WhatsApp app to see the response.");
723
+ }
724
+
725
+ main().catch(console.error);
726
+ ```
727
+
728
+ ### .env
729
+
730
+ ```env
731
+ VISITOR_ID_INSTANCE=your_visitor_instance_id
732
+ VISITOR_API_TOKEN=your_visitor_instance_token
733
+ AGENT_ID_INSTANCE=your_agent_instance_id
734
+ AGENT_API_TOKEN=your_agent_instance_token
735
+ AGENT_PHONE_NUMBER=your_agent_phone_number
736
+ WEBHOOK_URL=your_webhook_url
737
+ PORT=3000
738
+ ```
739
+
740
+ ## Real-World Examples
741
+
742
+ For complete real-world integration examples, check out:
743
+
744
+ - [Rocket.Chat Integration](link-to-rocket-chat-repo)
745
+
746
+ ## Best Practices
747
+
748
+ 1. **Message Transformation**:
749
+ - Handle only relevant message types
750
+
751
+ 2. **Security**:
752
+ - Validate all incoming webhooks
753
+ - Use secure tokens
754
+ - Implement rate limiting
755
+ - Use HTTPS for all endpoints
756
+
757
+ ## Utilities
758
+
759
+ The platform provides several utility functions:
760
+
761
+ ```typescript
762
+ // Format phone numbers for GREEN-API
763
+ formatPhoneNumber('1234567890') // Returns '1234567890@c.us'
764
+
765
+ // Generate secure random tokens
766
+ generateRandomToken(32) // Returns a 32-character random token
767
+ ```
768
+
769
+ ## License
770
+
771
+ MIT