@natyapp/meta 1.6.7 → 1.7.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/.github/copilot-instructions.md +1540 -0
- package/README.md +122 -1
- package/dist/index.d.ts +7 -2
- package/dist/index.js +11 -2
- package/dist/interfaces/IConnection.d.ts +2 -2
- package/dist/interfaces/ILog.d.ts +2 -2
- package/dist/interfaces/ILogger.d.ts +62 -0
- package/dist/interfaces/ILogger.js +2 -0
- package/dist/interfaces/ISdk.d.ts +4 -2
- package/dist/interfaces/IWebhook.d.ts +2 -2
- package/dist/interfaces/index.d.ts +1 -0
- package/dist/interfaces/index.js +1 -0
- package/dist/queue/messageQueue.d.ts +1 -1
- package/dist/queue/messageQueue.js +45 -0
- package/dist/routes/webhooks/methods/connection.js +78 -11
- package/dist/routes/webhooks/methods/messages.js +18 -3
- package/dist/services/axiosInstances.d.ts +14 -5
- package/dist/services/axiosInstances.js +111 -23
- package/dist/services/middlewares/validations.d.ts +2 -2
- package/dist/services/middlewares/validations.js +1 -2
- package/dist/services/mutations/connection.js +1 -1
- package/dist/services/mutations/logs.js +1 -1
- package/dist/services/mutations/messages.js +1 -1
- package/dist/services/mutations/validation.d.ts +1 -1
- package/dist/services/mutations/validation.js +1 -1
- package/dist/services/mutations/webhooks.js +1 -1
- package/dist/types/logs.d.ts +1 -1
- package/dist/types/requestTypes.d.ts +2 -0
- package/dist/useCases/connection/index.d.ts +9 -9
- package/dist/useCases/connection/index.js +156 -7
- package/dist/useCases/events/NatyEvents.d.ts +4 -2
- package/dist/useCases/events/NatyEvents.js +13 -1
- package/dist/useCases/log/index.d.ts +5 -5
- package/dist/useCases/log/index.js +65 -3
- package/dist/useCases/message/whatsappResponse.d.ts +33 -23
- package/dist/useCases/message/whatsappResponse.js +655 -109
- package/dist/useCases/messages/index.d.ts +5 -5
- package/dist/useCases/messages/index.js +66 -3
- package/dist/useCases/sdk/index.d.ts +8 -4
- package/dist/useCases/sdk/index.js +38 -6
- package/dist/useCases/webhook/index.d.ts +9 -9
- package/dist/useCases/webhook/index.js +154 -7
- package/dist/utils/consoleLogger.d.ts +20 -0
- package/dist/utils/consoleLogger.js +51 -0
- package/dist/utils/index.d.ts +6 -0
- package/dist/utils/index.js +6 -0
- package/dist/utils/loggerContext.d.ts +57 -0
- package/dist/utils/loggerContext.js +90 -0
- package/dist/utils/methodContext.d.ts +34 -0
- package/dist/utils/methodContext.js +48 -0
- package/dist/utils/parseError.d.ts +12 -0
- package/dist/utils/parseError.js +27 -3
- package/dist/utils/pinoAdapter.d.ts +30 -0
- package/dist/utils/pinoAdapter.js +68 -0
- package/dist/utils/sanitize.d.ts +42 -0
- package/dist/utils/sanitize.js +120 -0
- package/dist/utils/tryCatch.d.ts +10 -1
- package/dist/utils/tryCatch.js +40 -5
- package/docs/01-visao-geral.md +355 -0
- package/docs/02-contexto-negocio.md +596 -0
- package/docs/03-arquitetura.md +925 -0
- package/docs/04-fluxos-funcionais.md +887 -0
- package/docs/05-integracoes.md +960 -0
- package/docs/06-entidades.md +849 -0
- package/docs/07-guia-pratico.md +1133 -0
- package/docs/08-troubleshooting.md +816 -0
- package/docs/README.md +125 -0
- package/examples/logger-example.ts +279 -0
- package/package.json +2 -2
- /package/dist/{Entities → entities}/Logs.d.ts +0 -0
- /package/dist/{Entities → entities}/Logs.js +0 -0
- /package/dist/{Entities → entities}/connection.d.ts +0 -0
- /package/dist/{Entities → entities}/connection.js +0 -0
- /package/dist/{Entities → entities}/errorLogs.d.ts +0 -0
- /package/dist/{Entities → entities}/errorLogs.js +0 -0
- /package/dist/{Entities → entities}/index.d.ts +0 -0
- /package/dist/{Entities → entities}/index.js +0 -0
- /package/dist/{Entities → entities}/messages.d.ts +0 -0
- /package/dist/{Entities → entities}/messages.js +0 -0
- /package/dist/{Entities → entities}/webhooks.d.ts +0 -0
- /package/dist/{Entities → entities}/webhooks.js +0 -0
- /package/dist/{Entities → entities}/whatsappMessage.d.ts +0 -0
- /package/dist/{Entities → entities}/whatsappMessage.js +0 -0
- /package/dist/{Errors → errors}/Either.d.ts +0 -0
- /package/dist/{Errors → errors}/Either.js +0 -0
- /package/dist/{Errors → errors}/ErrorHandling.d.ts +0 -0
- /package/dist/{Errors → errors}/ErrorHandling.js +0 -0
- /package/dist/{Errors → errors}/index.d.ts +0 -0
- /package/dist/{Errors → errors}/index.js +0 -0
|
@@ -0,0 +1,1133 @@
|
|
|
1
|
+
# 07 - Guia Prático de Uso
|
|
2
|
+
|
|
3
|
+
[⬅️ Voltar ao Índice](README.md)
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 📋 Sumário
|
|
8
|
+
- [Setup Inicial](#-setup-inicial)
|
|
9
|
+
- [Exemplos de Envio de Mensagens](#-exemplos-de-envio-de-mensagens)
|
|
10
|
+
- [Exemplos de Recebimento de Mensagens](#-exemplos-de-recebimento-de-mensagens)
|
|
11
|
+
- [Trabalhando com Mídia](#-trabalhando-com-mídia)
|
|
12
|
+
- [Gestão de Conexões](#-gestão-de-conexões)
|
|
13
|
+
- [Gestão de Webhooks](#-gestão-de-webhooks)
|
|
14
|
+
- [Implementando um Chatbot Completo](#-implementando-um-chatbot-completo)
|
|
15
|
+
- [Best Practices](#-best-practices)
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## 🚀 Setup Inicial
|
|
20
|
+
|
|
21
|
+
### Passo 1: Instalação
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
# Usando npm
|
|
25
|
+
npm install @natyapp/meta
|
|
26
|
+
|
|
27
|
+
# Usando pnpm
|
|
28
|
+
pnpm add @natyapp/meta
|
|
29
|
+
|
|
30
|
+
# Usando yarn
|
|
31
|
+
yarn add @natyapp/meta
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Passo 2: Configuração de Variáveis de Ambiente
|
|
35
|
+
|
|
36
|
+
Crie um arquivo `.env` na raiz do projeto:
|
|
37
|
+
|
|
38
|
+
```env
|
|
39
|
+
# Obrigatório
|
|
40
|
+
API_META=https://api.meta.naty.app/v1
|
|
41
|
+
NATY_APP_TOKEN=seu_app_token_aqui
|
|
42
|
+
|
|
43
|
+
# Opcionais
|
|
44
|
+
NODE_ENV=development
|
|
45
|
+
PORT=3000
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
**Importante:** Adicione `.env` ao `.gitignore`:
|
|
49
|
+
|
|
50
|
+
```gitignore
|
|
51
|
+
# .gitignore
|
|
52
|
+
.env
|
|
53
|
+
.env.local
|
|
54
|
+
.env.*.local
|
|
55
|
+
node_modules/
|
|
56
|
+
dist/
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Passo 3: Estrutura de Projeto Recomendada
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
my-whatsapp-bot/
|
|
63
|
+
├── src/
|
|
64
|
+
│ ├── index.ts # Ponto de entrada
|
|
65
|
+
│ ├── sdk.ts # Inicialização do SDK
|
|
66
|
+
│ ├── handlers/ # Handlers de eventos
|
|
67
|
+
│ │ ├── messageHandler.ts
|
|
68
|
+
│ │ └── connectionHandler.ts
|
|
69
|
+
│ ├── services/ # Lógica de negócio
|
|
70
|
+
│ │ ├── chatbotService.ts
|
|
71
|
+
│ │ └── databaseService.ts
|
|
72
|
+
│ └── utils/ # Utilitários
|
|
73
|
+
│ └── logger.ts
|
|
74
|
+
├── .env
|
|
75
|
+
├── .gitignore
|
|
76
|
+
├── package.json
|
|
77
|
+
└── tsconfig.json
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Passo 4: Inicialização Básica
|
|
81
|
+
|
|
82
|
+
**Arquivo: `src/sdk.ts`**
|
|
83
|
+
|
|
84
|
+
```typescript
|
|
85
|
+
import { NatyMeta } from '@natyapp/meta';
|
|
86
|
+
import express from 'express';
|
|
87
|
+
import dotenv from 'dotenv';
|
|
88
|
+
|
|
89
|
+
dotenv.config();
|
|
90
|
+
|
|
91
|
+
// Criar instância Express
|
|
92
|
+
const app = express();
|
|
93
|
+
app.use(express.json());
|
|
94
|
+
|
|
95
|
+
// Inicializar SDK
|
|
96
|
+
const sdk = new NatyMeta();
|
|
97
|
+
|
|
98
|
+
export async function initializeSDK() {
|
|
99
|
+
const result = await sdk.connect({
|
|
100
|
+
appToken: process.env.NATY_APP_TOKEN!,
|
|
101
|
+
app: app,
|
|
102
|
+
pathname: '/webhooks'
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
if (result.isLeft()) {
|
|
106
|
+
console.error('Erro ao inicializar SDK:', result.value);
|
|
107
|
+
process.exit(1);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
console.log('✅ SDK inicializado com sucesso!');
|
|
111
|
+
return sdk;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export { sdk, app };
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
**Arquivo: `src/index.ts`**
|
|
118
|
+
|
|
119
|
+
```typescript
|
|
120
|
+
import { initializeSDK, app } from './sdk';
|
|
121
|
+
import './handlers/messageHandler'; // Registra listeners
|
|
122
|
+
import './handlers/connectionHandler';
|
|
123
|
+
|
|
124
|
+
async function main() {
|
|
125
|
+
// Inicializar SDK
|
|
126
|
+
await initializeSDK();
|
|
127
|
+
|
|
128
|
+
// Iniciar servidor
|
|
129
|
+
const PORT = process.env.PORT || 3000;
|
|
130
|
+
app.listen(PORT, () => {
|
|
131
|
+
console.log(`🚀 Servidor rodando na porta ${PORT}`);
|
|
132
|
+
console.log(`📥 Webhook: http://localhost:${PORT}/webhooks/messages`);
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
main().catch(console.error);
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### Passo 5: Configuração de Logger (Opcional mas Recomendado)
|
|
140
|
+
|
|
141
|
+
O SDK suporta loggers customizados para melhor observabilidade em produção.
|
|
142
|
+
|
|
143
|
+
#### Usando Pino Logger (Recomendado)
|
|
144
|
+
|
|
145
|
+
**Instalar dependências:**
|
|
146
|
+
```bash
|
|
147
|
+
npm install pino pino-pretty
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
**Arquivo: `src/utils/logger.ts`**
|
|
151
|
+
|
|
152
|
+
```typescript
|
|
153
|
+
import pino from 'pino';
|
|
154
|
+
import { createPinoAdapter } from '@natyapp/meta';
|
|
155
|
+
|
|
156
|
+
export const logger = pino({
|
|
157
|
+
level: process.env.LOG_LEVEL || 'info',
|
|
158
|
+
transport: process.env.NODE_ENV === 'development' ? {
|
|
159
|
+
target: 'pino-pretty',
|
|
160
|
+
options: {
|
|
161
|
+
colorize: true,
|
|
162
|
+
translateTime: 'SYS:HH:MM:ss',
|
|
163
|
+
ignore: 'pid,hostname'
|
|
164
|
+
}
|
|
165
|
+
} : undefined
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
export const sdkLogger = createPinoAdapter(logger);
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
**Atualizar `src/sdk.ts`:**
|
|
172
|
+
|
|
173
|
+
```typescript
|
|
174
|
+
import { NatyMeta } from '@natyapp/meta';
|
|
175
|
+
import { sdkLogger, logger } from './utils/logger';
|
|
176
|
+
|
|
177
|
+
const sdk = new NatyMeta({
|
|
178
|
+
logger: sdkLogger // Injeta logger customizado
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
export async function initializeSDK() {
|
|
182
|
+
const result = await sdk.connect({
|
|
183
|
+
appToken: process.env.NATY_APP_TOKEN!,
|
|
184
|
+
app: app,
|
|
185
|
+
pathname: '/webhooks'
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
if (result.isError) {
|
|
189
|
+
logger.error({ error: result.isError }, 'Erro ao inicializar SDK');
|
|
190
|
+
process.exit(1);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
logger.info('✅ SDK inicializado com sucesso!');
|
|
194
|
+
return sdk;
|
|
195
|
+
}
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
**Logs disponíveis:**
|
|
199
|
+
- ✅ HTTP requests/responses (nível debug)
|
|
200
|
+
- ✅ Token refresh operations (nível info)
|
|
201
|
+
- ✅ Message sending/receiving (nível info)
|
|
202
|
+
- ✅ Webhook processing (nível info)
|
|
203
|
+
- ✅ Errors with context (nível error)
|
|
204
|
+
|
|
205
|
+
---
|
|
206
|
+
|
|
207
|
+
## 📤 Exemplos de Envio de Mensagens
|
|
208
|
+
|
|
209
|
+
### Exemplo 1: Mensagem de Texto Simples
|
|
210
|
+
|
|
211
|
+
```typescript
|
|
212
|
+
import { sdk } from './sdk';
|
|
213
|
+
|
|
214
|
+
async function sendTextMessage() {
|
|
215
|
+
const whatsapp = sdk.Message.WhatsappResponse({
|
|
216
|
+
companyId: 'abc123',
|
|
217
|
+
phone_number_id: '123456789012345'
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
const result = await whatsapp.send_text({
|
|
221
|
+
to: '5511999999999',
|
|
222
|
+
message: 'Olá! Bem-vindo ao nosso atendimento.'
|
|
223
|
+
predense: true
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
if (result.isRight()) {
|
|
227
|
+
console.log('Mensagem enviada! ID:', result.value.messages[0].id);
|
|
228
|
+
} else {
|
|
229
|
+
console.error('Erro:', result.value);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
### Exemplo 2: Mensagem com Link Preview
|
|
235
|
+
|
|
236
|
+
```typescript
|
|
237
|
+
async function sendTextWithPreview() {
|
|
238
|
+
const whatsapp = sdk.Message.WhatsappResponse({
|
|
239
|
+
companyId: 'abc123',
|
|
240
|
+
phone_number_id: '123456789012345'
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
const result = await whatsapp.send_text({
|
|
244
|
+
to: '5511999999999',
|
|
245
|
+
message: 'Confira nosso site: https://www.minhaempresa.com.br',
|
|
246
|
+
preview_url: true // Exibe preview do link
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
if (result.isRight()) {
|
|
250
|
+
console.log('Mensagem com preview enviada!');
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
### Exemplo 3: Botões Interativos
|
|
256
|
+
|
|
257
|
+
```typescript
|
|
258
|
+
import { Button } from '@natyapp/meta';
|
|
259
|
+
|
|
260
|
+
async function sendButtonMessage() {
|
|
261
|
+
const whatsapp = sdk.Message.WhatsappResponse({
|
|
262
|
+
companyId: 'abc123',
|
|
263
|
+
phone_number_id: '123456789012345'
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
// Construir mensagem com botões
|
|
267
|
+
const buttonPayload = new Button()
|
|
268
|
+
.setBody('Como podemos ajudar você hoje?')
|
|
269
|
+
.addButton({ id: 'suporte', title: '💬 Suporte' })
|
|
270
|
+
.addButton({ id: 'vendas', title: '🛒 Vendas' })
|
|
271
|
+
.addButton({ id: 'financeiro', title: '💰 Financeiro' })
|
|
272
|
+
.build();
|
|
273
|
+
|
|
274
|
+
const result = await whatsapp.send_buttons({
|
|
275
|
+
to: '5511999999999',
|
|
276
|
+
...buttonPayload
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
if (result.isRight()) {
|
|
280
|
+
console.log('Botões enviados!');
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
### Exemplo 4: Lista de Opções
|
|
286
|
+
|
|
287
|
+
```typescript
|
|
288
|
+
import { List } from '@natyapp/meta';
|
|
289
|
+
|
|
290
|
+
async function sendListMessage() {
|
|
291
|
+
const whatsapp = sdk.Message.WhatsappResponse({
|
|
292
|
+
companyId: 'abc123',
|
|
293
|
+
phone_number_id: '123456789012345'
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
// Construir lista com múltiplas seções
|
|
297
|
+
const listPayload = new List()
|
|
298
|
+
.setBody('Confira nossos produtos e serviços:')
|
|
299
|
+
.setButtonText('📋 Ver Opções')
|
|
300
|
+
.addSection('Produtos')
|
|
301
|
+
.addItem({
|
|
302
|
+
id: 'prod_smartphone',
|
|
303
|
+
title: '📱 Smartphones',
|
|
304
|
+
description: 'Últimos modelos disponíveis'
|
|
305
|
+
})
|
|
306
|
+
.addItem({
|
|
307
|
+
id: 'prod_notebook',
|
|
308
|
+
title: '💻 Notebooks',
|
|
309
|
+
description: 'Alta performance'
|
|
310
|
+
})
|
|
311
|
+
.addSection('Serviços')
|
|
312
|
+
.addItem({
|
|
313
|
+
id: 'serv_suporte',
|
|
314
|
+
title: '🔧 Suporte Técnico',
|
|
315
|
+
description: 'Atendimento especializado'
|
|
316
|
+
})
|
|
317
|
+
.addItem({
|
|
318
|
+
id: 'serv_garantia',
|
|
319
|
+
title: '🛡️ Garantia Estendida',
|
|
320
|
+
description: 'Proteção completa'
|
|
321
|
+
})
|
|
322
|
+
.build();
|
|
323
|
+
|
|
324
|
+
const result = await whatsapp.send_list({
|
|
325
|
+
to: '5511999999999',
|
|
326
|
+
...listPayload
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
if (result.isRight()) {
|
|
330
|
+
console.log('Lista enviada!');
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
### Exemplo 5: Imagem com Legenda
|
|
336
|
+
|
|
337
|
+
```typescript
|
|
338
|
+
async function sendImageMessage() {
|
|
339
|
+
const whatsapp = sdk.Message.WhatsappResponse({
|
|
340
|
+
companyId: 'abc123',
|
|
341
|
+
phone_number_id: '123456789012345'
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
const result = await whatsapp.send_image({
|
|
345
|
+
to: '5511999999999',
|
|
346
|
+
url: 'https://exemplo.com/produtos/smartphone.jpg',
|
|
347
|
+
caption: '📱 Novo Smartphone X Pro - Disponível agora!'
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
if (result.isRight()) {
|
|
351
|
+
console.log('Imagem enviada!');
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
### Exemplo 6: Vídeo
|
|
357
|
+
|
|
358
|
+
```typescript
|
|
359
|
+
async function sendVideoMessage() {
|
|
360
|
+
const whatsapp = sdk.Message.WhatsappResponse({
|
|
361
|
+
companyId: 'abc123',
|
|
362
|
+
phone_number_id: '123456789012345'
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
const result = await whatsapp.send_video({
|
|
366
|
+
to: '5511999999999',
|
|
367
|
+
url: 'https://exemplo.com/videos/tutorial.mp4',
|
|
368
|
+
caption: '🎥 Tutorial: Como usar nosso produto'
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
if (result.isRight()) {
|
|
372
|
+
console.log('Vídeo enviado!');
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
### Exemplo 7: Documento PDF
|
|
378
|
+
|
|
379
|
+
```typescript
|
|
380
|
+
async function sendDocumentMessage() {
|
|
381
|
+
const whatsapp = sdk.Message.WhatsappResponse({
|
|
382
|
+
companyId: 'abc123',
|
|
383
|
+
phone_number_id: '123456789012345'
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
const result = await whatsapp.send_document({
|
|
387
|
+
to: '5511999999999',
|
|
388
|
+
url: 'https://exemplo.com/documentos/catalogo.pdf',
|
|
389
|
+
filename: 'Catálogo_2026.pdf',
|
|
390
|
+
caption: '📄 Catálogo completo de produtos'
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
if (result.isRight()) {
|
|
394
|
+
console.log('Documento enviado!');
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
### Exemplo 8: Localização
|
|
400
|
+
|
|
401
|
+
```typescript
|
|
402
|
+
async function sendLocationMessage() {
|
|
403
|
+
const whatsapp = sdk.Message.WhatsappResponse({
|
|
404
|
+
companyId: 'abc123',
|
|
405
|
+
phone_number_id: '123456789012345'
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
const result = await whatsapp.send_location({
|
|
409
|
+
to: '5511999999999',
|
|
410
|
+
latitude: -23.5505199,
|
|
411
|
+
longitude: -46.6333094,
|
|
412
|
+
name: 'Minha Empresa LTDA',
|
|
413
|
+
address: 'Av. Paulista, 1000 - São Paulo, SP'
|
|
414
|
+
});
|
|
415
|
+
|
|
416
|
+
if (result.isRight()) {
|
|
417
|
+
console.log('Localização enviada!');
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
### Exemplo 9: Template Aprovado
|
|
423
|
+
|
|
424
|
+
```typescript
|
|
425
|
+
async function sendTemplateMessage() {
|
|
426
|
+
const whatsapp = sdk.Message.WhatsappResponse({
|
|
427
|
+
companyId: 'abc123',
|
|
428
|
+
phone_number_id: '123456789012345'
|
|
429
|
+
});
|
|
430
|
+
|
|
431
|
+
const result = await whatsapp.send_text_template({
|
|
432
|
+
to: '5511999999999',
|
|
433
|
+
template: {
|
|
434
|
+
name: 'confirmacao_pedido', // Nome do template aprovado pela Meta
|
|
435
|
+
language: 'pt_BR',
|
|
436
|
+
components: [
|
|
437
|
+
{
|
|
438
|
+
type: 'body',
|
|
439
|
+
parameters: [
|
|
440
|
+
{ type: 'text', text: 'João Silva' }, // {{1}}
|
|
441
|
+
{ type: 'text', text: '#12345' }, // {{2}}
|
|
442
|
+
{ type: 'text', text: 'R$ 250,00' } // {{3}}
|
|
443
|
+
]
|
|
444
|
+
}
|
|
445
|
+
]
|
|
446
|
+
}
|
|
447
|
+
});
|
|
448
|
+
|
|
449
|
+
if (result.isRight()) {
|
|
450
|
+
console.log('Template enviado!');
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
### Exemplo 10: Marcar como Lido
|
|
456
|
+
|
|
457
|
+
```typescript
|
|
458
|
+
async function markAsRead(messageId: string) {
|
|
459
|
+
const whatsapp = sdk.Message.WhatsappResponse({
|
|
460
|
+
companyId: 'abc123',
|
|
461
|
+
phone_number_id: '123456789012345'
|
|
462
|
+
});
|
|
463
|
+
|
|
464
|
+
const result = await whatsapp.mark_as_read(messageId);
|
|
465
|
+
|
|
466
|
+
if (result.isRight()) {
|
|
467
|
+
console.log('Mensagem marcada como lida!');
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
---
|
|
473
|
+
|
|
474
|
+
## 📥 Exemplos de Recebimento de Mensagens
|
|
475
|
+
|
|
476
|
+
### Exemplo 1: Handler Básico
|
|
477
|
+
|
|
478
|
+
**Arquivo: `src/handlers/messageHandler.ts`**
|
|
479
|
+
|
|
480
|
+
```typescript
|
|
481
|
+
import { sdk } from '../sdk';
|
|
482
|
+
|
|
483
|
+
sdk.on('message', async (data) => {
|
|
484
|
+
console.log('=== Nova Mensagem ===');
|
|
485
|
+
console.log('De:', data.sender);
|
|
486
|
+
console.log('Tipo:', data.message.type);
|
|
487
|
+
console.log('Mensagem:', data.message);
|
|
488
|
+
|
|
489
|
+
// Responder automaticamente
|
|
490
|
+
await data.whatsappResponse.send_text({
|
|
491
|
+
to: data.sender,
|
|
492
|
+
message: 'Mensagem recebida! Em breve responderemos.'
|
|
493
|
+
});
|
|
494
|
+
});
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
### Exemplo 2: Processamento por Tipo de Mensagem
|
|
498
|
+
|
|
499
|
+
```typescript
|
|
500
|
+
import { sdk } from '../sdk';
|
|
501
|
+
|
|
502
|
+
sdk.on('message', async (data) => {
|
|
503
|
+
const { message, sender, whatsappResponse } = data;
|
|
504
|
+
|
|
505
|
+
switch (message.type) {
|
|
506
|
+
case 'text':
|
|
507
|
+
await handleTextMessage(message.text.body, sender, whatsappResponse);
|
|
508
|
+
break;
|
|
509
|
+
|
|
510
|
+
case 'image':
|
|
511
|
+
await handleImageMessage(message.image, sender, whatsappResponse);
|
|
512
|
+
break;
|
|
513
|
+
|
|
514
|
+
case 'interactive':
|
|
515
|
+
await handleInteractiveMessage(message.interactive, sender, whatsappResponse);
|
|
516
|
+
break;
|
|
517
|
+
|
|
518
|
+
default:
|
|
519
|
+
console.log(`Tipo não tratado: ${message.type}`);
|
|
520
|
+
}
|
|
521
|
+
});
|
|
522
|
+
|
|
523
|
+
async function handleTextMessage(text: string, sender: string, whatsapp: any) {
|
|
524
|
+
console.log(`Texto recebido: "${text}"`);
|
|
525
|
+
|
|
526
|
+
const lowerText = text.toLowerCase();
|
|
527
|
+
|
|
528
|
+
if (lowerText.includes('oi') || lowerText.includes('olá')) {
|
|
529
|
+
await whatsapp.send_text({
|
|
530
|
+
to: sender,
|
|
531
|
+
message: 'Olá! Bem-vindo. Como posso ajudar?'
|
|
532
|
+
});
|
|
533
|
+
} else if (lowerText.includes('preço') || lowerText.includes('valor')) {
|
|
534
|
+
await whatsapp.send_text({
|
|
535
|
+
to: sender,
|
|
536
|
+
message: 'Para consultar preços, digite CATALOGO.'
|
|
537
|
+
});
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
async function handleImageMessage(image: any, sender: string, whatsapp: any) {
|
|
542
|
+
console.log(`Imagem recebida: ${image.id}`);
|
|
543
|
+
|
|
544
|
+
// Download automático
|
|
545
|
+
const downloadResult = await whatsapp.download_media(image.id);
|
|
546
|
+
|
|
547
|
+
if (downloadResult.isRight()) {
|
|
548
|
+
console.log('Imagem baixada com sucesso!');
|
|
549
|
+
// Processar imagem (ex: análise, OCR, salvar em disco)
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
await whatsapp.send_text({
|
|
553
|
+
to: sender,
|
|
554
|
+
message: 'Imagem recebida! Estamos analisando.'
|
|
555
|
+
});
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
async function handleInteractiveMessage(interactive: any, sender: string, whatsapp: any) {
|
|
559
|
+
const buttonId = interactive.button_reply?.id || interactive.list_reply?.id;
|
|
560
|
+
|
|
561
|
+
console.log(`Botão/Item selecionado: ${buttonId}`);
|
|
562
|
+
|
|
563
|
+
// Processar seleção
|
|
564
|
+
switch (buttonId) {
|
|
565
|
+
case 'suporte':
|
|
566
|
+
await whatsapp.send_text({
|
|
567
|
+
to: sender,
|
|
568
|
+
message: 'Você foi direcionado para o suporte. Aguarde...'
|
|
569
|
+
});
|
|
570
|
+
break;
|
|
571
|
+
|
|
572
|
+
case 'vendas':
|
|
573
|
+
await whatsapp.send_text({
|
|
574
|
+
to: sender,
|
|
575
|
+
message: 'Equipe de vendas: (11) 99999-9999'
|
|
576
|
+
});
|
|
577
|
+
break;
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
```
|
|
581
|
+
|
|
582
|
+
### Exemplo 3: Sistema de Contextos/Conversação
|
|
583
|
+
|
|
584
|
+
```typescript
|
|
585
|
+
import { sdk } from '../sdk';
|
|
586
|
+
|
|
587
|
+
// Armazenar contextos de conversação
|
|
588
|
+
const userContexts = new Map<string, ConversationContext>();
|
|
589
|
+
|
|
590
|
+
interface ConversationContext {
|
|
591
|
+
state: string;
|
|
592
|
+
data: Record<string, any>;
|
|
593
|
+
lastInteraction: Date;
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
sdk.on('message', async (data) => {
|
|
597
|
+
const { sender, message, whatsappResponse } = data;
|
|
598
|
+
|
|
599
|
+
// Obter ou criar contexto
|
|
600
|
+
let context = userContexts.get(sender);
|
|
601
|
+
if (!context) {
|
|
602
|
+
context = {
|
|
603
|
+
state: 'initial',
|
|
604
|
+
data: {},
|
|
605
|
+
lastInteraction: new Date()
|
|
606
|
+
};
|
|
607
|
+
userContexts.set(sender, context);
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
// Atualizar last interaction
|
|
611
|
+
context.lastInteraction = new Date();
|
|
612
|
+
|
|
613
|
+
// Processar baseado no estado
|
|
614
|
+
await processConversation(context, message, sender, whatsappResponse);
|
|
615
|
+
});
|
|
616
|
+
|
|
617
|
+
async function processConversation(
|
|
618
|
+
context: ConversationContext,
|
|
619
|
+
message: any,
|
|
620
|
+
sender: string,
|
|
621
|
+
whatsapp: any
|
|
622
|
+
) {
|
|
623
|
+
const text = message.text?.body.toLowerCase() || '';
|
|
624
|
+
|
|
625
|
+
switch (context.state) {
|
|
626
|
+
case 'initial':
|
|
627
|
+
await whatsapp.send_text({
|
|
628
|
+
to: sender,
|
|
629
|
+
message: 'Olá! Para começar, qual é o seu nome?'
|
|
630
|
+
});
|
|
631
|
+
context.state = 'collecting_name';
|
|
632
|
+
break;
|
|
633
|
+
|
|
634
|
+
case 'collecting_name':
|
|
635
|
+
context.data.name = message.text.body;
|
|
636
|
+
await whatsapp.send_text({
|
|
637
|
+
to: sender,
|
|
638
|
+
message: `Prazer, ${context.data.name}! Qual é o seu email?`
|
|
639
|
+
});
|
|
640
|
+
context.state = 'collecting_email';
|
|
641
|
+
break;
|
|
642
|
+
|
|
643
|
+
case 'collecting_email':
|
|
644
|
+
context.data.email = message.text.body;
|
|
645
|
+
await whatsapp.send_text({
|
|
646
|
+
to: sender,
|
|
647
|
+
message: `Perfeito! Seu cadastro foi completo.\n\nNome: ${context.data.name}\nEmail: ${context.data.email}`
|
|
648
|
+
});
|
|
649
|
+
|
|
650
|
+
// Salvar no banco de dados
|
|
651
|
+
await saveUserToDatabase(context.data);
|
|
652
|
+
|
|
653
|
+
// Resetar contexto
|
|
654
|
+
userContexts.delete(sender);
|
|
655
|
+
break;
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
async function saveUserToDatabase(data: any) {
|
|
660
|
+
console.log('Salvando usuário:', data);
|
|
661
|
+
// Implementar lógica de salvamento
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
// Limpar contextos antigos a cada 30 minutos
|
|
665
|
+
setInterval(() => {
|
|
666
|
+
const now = new Date();
|
|
667
|
+
for (const [sender, context] of userContexts.entries()) {
|
|
668
|
+
const diffMinutes = (now.getTime() - context.lastInteraction.getTime()) / 1000 / 60;
|
|
669
|
+
if (diffMinutes > 30) {
|
|
670
|
+
userContexts.delete(sender);
|
|
671
|
+
console.log(`Contexto expirado para ${sender}`);
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
}, 30 * 60 * 1000);
|
|
675
|
+
```
|
|
676
|
+
|
|
677
|
+
---
|
|
678
|
+
|
|
679
|
+
## 🎞 Trabalhando com Mídia
|
|
680
|
+
|
|
681
|
+
### Upload de Arquivo Local
|
|
682
|
+
|
|
683
|
+
```typescript
|
|
684
|
+
import fs from 'fs';
|
|
685
|
+
import { sdk } from './sdk';
|
|
686
|
+
|
|
687
|
+
async function uploadLocalFile() {
|
|
688
|
+
const whatsapp = sdk.Message.WhatsappResponse({
|
|
689
|
+
companyId: 'abc123',
|
|
690
|
+
phone_number_id: '123456789012345'
|
|
691
|
+
});
|
|
692
|
+
|
|
693
|
+
// Criar stream de leitura
|
|
694
|
+
const stream = fs.createReadStream('./assets/product.jpg');
|
|
695
|
+
|
|
696
|
+
// Upload
|
|
697
|
+
const uploadResult = await whatsapp.createMedia(stream);
|
|
698
|
+
|
|
699
|
+
if (uploadResult.isRight()) {
|
|
700
|
+
const mediaId = uploadResult.value.id;
|
|
701
|
+
console.log('Upload concluído! Media ID:', mediaId);
|
|
702
|
+
|
|
703
|
+
// Enviar usando media_id
|
|
704
|
+
const sendResult = await whatsapp.send_image({
|
|
705
|
+
to: '5511999999999',
|
|
706
|
+
media_id: mediaId,
|
|
707
|
+
caption: 'Produto em destaque!'
|
|
708
|
+
});
|
|
709
|
+
|
|
710
|
+
if (sendResult.isRight()) {
|
|
711
|
+
console.log('Imagem enviada!');
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
```
|
|
716
|
+
|
|
717
|
+
### Download de Mídia Recebida
|
|
718
|
+
|
|
719
|
+
```typescript
|
|
720
|
+
import fs from 'fs';
|
|
721
|
+
import { sdk } from './sdk';
|
|
722
|
+
|
|
723
|
+
sdk.on('message', async (data) => {
|
|
724
|
+
if (data.message.type === 'image') {
|
|
725
|
+
const mediaId = data.message.image.id;
|
|
726
|
+
|
|
727
|
+
// Download como buffer
|
|
728
|
+
const downloadResult = await data.whatsappResponse.download_media(mediaId);
|
|
729
|
+
|
|
730
|
+
if (downloadResult.isRight()) {
|
|
731
|
+
const imageBuffer = downloadResult.value;
|
|
732
|
+
|
|
733
|
+
// Salvar em disco
|
|
734
|
+
const filename = `./downloads/${Date.now()}_${mediaId}.jpg`;
|
|
735
|
+
fs.writeFileSync(filename, imageBuffer);
|
|
736
|
+
console.log(`Imagem salva em: ${filename}`);
|
|
737
|
+
|
|
738
|
+
// Ou processar diretamente
|
|
739
|
+
await processImage(imageBuffer);
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
});
|
|
743
|
+
|
|
744
|
+
async function processImage(buffer: Buffer) {
|
|
745
|
+
// Exemplo: Análise com IA, OCR, etc.
|
|
746
|
+
console.log(`Processando imagem de ${buffer.length} bytes`);
|
|
747
|
+
}
|
|
748
|
+
```
|
|
749
|
+
|
|
750
|
+
---
|
|
751
|
+
|
|
752
|
+
## 🔧 Gestão de Conexões
|
|
753
|
+
|
|
754
|
+
### Criar Nova Conexão
|
|
755
|
+
|
|
756
|
+
```typescript
|
|
757
|
+
import { sdk } from './sdk';
|
|
758
|
+
|
|
759
|
+
async function createNewConnection() {
|
|
760
|
+
const result = await sdk.Connection.create({
|
|
761
|
+
companyId: 'abc123',
|
|
762
|
+
phoneNumberId: '123456789012345',
|
|
763
|
+
phoneNumber: '+5511999999999',
|
|
764
|
+
accessToken: 'EAAxxxxxxxxxxxxxxxxx',
|
|
765
|
+
appId: '123456789',
|
|
766
|
+
appSecret: 'abcdef1234567890',
|
|
767
|
+
accountId: '987654321',
|
|
768
|
+
businessId: '456789123'
|
|
769
|
+
});
|
|
770
|
+
|
|
771
|
+
if (result.isRight()) {
|
|
772
|
+
console.log('Conexão criada:', result.value);
|
|
773
|
+
} else {
|
|
774
|
+
console.error('Erro ao criar conexão:', result.value);
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
```
|
|
778
|
+
|
|
779
|
+
### Buscar Conexão
|
|
780
|
+
|
|
781
|
+
```typescript
|
|
782
|
+
async function getConnectionInfo() {
|
|
783
|
+
const result = await sdk.Connection.get({
|
|
784
|
+
companyId: 'abc123',
|
|
785
|
+
phoneNumberId: '123456789012345'
|
|
786
|
+
});
|
|
787
|
+
|
|
788
|
+
if (result.isRight()) {
|
|
789
|
+
const connection = result.value;
|
|
790
|
+
console.log('Conexão encontrada:');
|
|
791
|
+
console.log('ID:', connection.id);
|
|
792
|
+
console.log('Número:', connection.phoneNumber);
|
|
793
|
+
console.log('Ativa:', connection.isActive);
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
```
|
|
797
|
+
|
|
798
|
+
### Atualizar Token
|
|
799
|
+
|
|
800
|
+
```typescript
|
|
801
|
+
async function updateConnectionToken(connectionId: string, newToken: string) {
|
|
802
|
+
const result = await sdk.Connection.update(connectionId, {
|
|
803
|
+
accessToken: newToken
|
|
804
|
+
});
|
|
805
|
+
|
|
806
|
+
if (result.isRight()) {
|
|
807
|
+
console.log('Token atualizado com sucesso!');
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
```
|
|
811
|
+
|
|
812
|
+
### Listar Todas as Conexões
|
|
813
|
+
|
|
814
|
+
```typescript
|
|
815
|
+
async function listAllConnections(companyId: string) {
|
|
816
|
+
const result = await sdk.Connection.list({ companyId });
|
|
817
|
+
|
|
818
|
+
if (result.isRight()) {
|
|
819
|
+
const connections = result.value;
|
|
820
|
+
console.log(`Total de conexões: ${connections.length}`);
|
|
821
|
+
|
|
822
|
+
connections.forEach(conn => {
|
|
823
|
+
console.log(`- ${conn.phoneNumber} (${conn.isActive ? 'Ativa' : 'Inativa'})`);
|
|
824
|
+
});
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
```
|
|
828
|
+
|
|
829
|
+
---
|
|
830
|
+
|
|
831
|
+
## 🪝 Gestão de Webhooks
|
|
832
|
+
|
|
833
|
+
### Configurar Webhooks
|
|
834
|
+
|
|
835
|
+
```typescript
|
|
836
|
+
import { sdk } from './sdk';
|
|
837
|
+
|
|
838
|
+
async function setupWebhooks() {
|
|
839
|
+
const result = await sdk.Webhook.create({
|
|
840
|
+
companyId: 'abc123',
|
|
841
|
+
connection: {
|
|
842
|
+
url: 'https://meuapp.com/webhooks/connections',
|
|
843
|
+
active: true
|
|
844
|
+
},
|
|
845
|
+
messages: {
|
|
846
|
+
url: 'https://meuapp.com/webhooks/messages',
|
|
847
|
+
active: true
|
|
848
|
+
}
|
|
849
|
+
});
|
|
850
|
+
|
|
851
|
+
if (result.isRight()) {
|
|
852
|
+
console.log('Webhooks configurados:', result.value);
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
```
|
|
856
|
+
|
|
857
|
+
### Desativar Webhook Temporariamente
|
|
858
|
+
|
|
859
|
+
```typescript
|
|
860
|
+
async function disableMessageWebhook(webhookId: string) {
|
|
861
|
+
const result = await sdk.Webhook.update(webhookId, {
|
|
862
|
+
messages: {
|
|
863
|
+
url: 'https://meuapp.com/webhooks/messages',
|
|
864
|
+
active: false // Desativa
|
|
865
|
+
}
|
|
866
|
+
});
|
|
867
|
+
|
|
868
|
+
if (result.isRight()) {
|
|
869
|
+
console.log('Webhook de mensagens desativado');
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
```
|
|
873
|
+
|
|
874
|
+
---
|
|
875
|
+
|
|
876
|
+
## 🤖 Implementando um Chatbot Completo
|
|
877
|
+
|
|
878
|
+
### Chatbot com IA (Exemplo Completo)
|
|
879
|
+
|
|
880
|
+
```typescript
|
|
881
|
+
import { sdk } from './sdk';
|
|
882
|
+
import { Button, List } from '@natyapp/meta';
|
|
883
|
+
|
|
884
|
+
// Simulação de serviço de IA
|
|
885
|
+
async function getAIResponse(userMessage: string): Promise<string> {
|
|
886
|
+
// Aqui você integraria com OpenAI, DialogFlow, etc.
|
|
887
|
+
const responses: Record<string, string> = {
|
|
888
|
+
'horário': 'Atendemos de segunda a sexta, das 9h às 18h.',
|
|
889
|
+
'preço': 'Nossos produtos variam de R$ 50 a R$ 5.000.',
|
|
890
|
+
'entrega': 'Entregamos em todo o Brasil em até 7 dias úteis.',
|
|
891
|
+
};
|
|
892
|
+
|
|
893
|
+
for (const [key, response] of Object.entries(responses)) {
|
|
894
|
+
if (userMessage.toLowerCase().includes(key)) {
|
|
895
|
+
return response;
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
return 'Desculpe, não entendi. Digite MENU para ver as opções disponíveis.';
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
// Handler principal
|
|
903
|
+
sdk.on('message', async (data) => {
|
|
904
|
+
const { sender, message, whatsappResponse } = data;
|
|
905
|
+
|
|
906
|
+
// Logs
|
|
907
|
+
console.log(`[${new Date().toISOString()}] Mensagem de ${sender}`);
|
|
908
|
+
|
|
909
|
+
// Processar por tipo
|
|
910
|
+
if (message.type === 'text') {
|
|
911
|
+
const userText = message.text.body.trim();
|
|
912
|
+
|
|
913
|
+
// Comandos especiais
|
|
914
|
+
if (userText.toUpperCase() === 'MENU') {
|
|
915
|
+
await sendMainMenu(sender, whatsappResponse);
|
|
916
|
+
return;
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
if (userText.toUpperCase() === 'CATALOGO') {
|
|
920
|
+
await sendCatalog(sender, whatsappResponse);
|
|
921
|
+
return;
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
// Processar com IA
|
|
925
|
+
const aiResponse = await getAIResponse(userText);
|
|
926
|
+
await whatsappResponse.send_text({
|
|
927
|
+
to: sender,
|
|
928
|
+
message: aiResponse
|
|
929
|
+
});
|
|
930
|
+
|
|
931
|
+
} else if (message.type === 'interactive') {
|
|
932
|
+
await handleInteractiveSelection(message.interactive, sender, whatsappResponse);
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
// Marcar como lido
|
|
936
|
+
await whatsappResponse.mark_as_read(message.id);
|
|
937
|
+
});
|
|
938
|
+
|
|
939
|
+
async function sendMainMenu(to: string, whatsapp: any) {
|
|
940
|
+
const buttons = new Button()
|
|
941
|
+
.setBody('🏠 *Menu Principal*\n\nEscolha uma opção:')
|
|
942
|
+
.addButton({ id: 'products', title: '🛍️ Produtos' })
|
|
943
|
+
.addButton({ id: 'support', title: '💬 Suporte' })
|
|
944
|
+
.addButton({ id: 'about', title: 'ℹ️ Sobre Nós' })
|
|
945
|
+
.build();
|
|
946
|
+
|
|
947
|
+
await whatsapp.send_buttons({ to, ...buttons });
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
async function sendCatalog(to: string, whatsapp: any) {
|
|
951
|
+
const list = new List()
|
|
952
|
+
.setBody('📱 *Catálogo de Produtos*\n\nSelecione uma categoria:')
|
|
953
|
+
.setButtonText('Ver Catálogo')
|
|
954
|
+
.addSection('Eletrônicos')
|
|
955
|
+
.addItem({ id: 'cat_smartphones', title: 'Smartphones', description: 'Últimos modelos' })
|
|
956
|
+
.addItem({ id: 'cat_notebooks', title: 'Notebooks', description: 'Alta performance' })
|
|
957
|
+
.addSection('Acessórios')
|
|
958
|
+
.addItem({ id: 'cat_fones', title: 'Fones de Ouvido', description: 'Som premium' })
|
|
959
|
+
.addItem({ id: 'cat_capas', title: 'Capas e Películas', description: 'Proteção total' })
|
|
960
|
+
.build();
|
|
961
|
+
|
|
962
|
+
await whatsapp.send_list({ to, ...list });
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
async function handleInteractiveSelection(interactive: any, sender: string, whatsapp: any) {
|
|
966
|
+
const selectedId = interactive.button_reply?.id || interactive.list_reply?.id;
|
|
967
|
+
|
|
968
|
+
console.log(`Usuário selecionou: ${selectedId}`);
|
|
969
|
+
|
|
970
|
+
switch (selectedId) {
|
|
971
|
+
case 'products':
|
|
972
|
+
await sendCatalog(sender, whatsapp);
|
|
973
|
+
break;
|
|
974
|
+
|
|
975
|
+
case 'support':
|
|
976
|
+
await whatsapp.send_text({
|
|
977
|
+
to: sender,
|
|
978
|
+
message: '💬 *Suporte*\n\nWhatsApp: (11) 99999-9999\nEmail: suporte@empresa.com\nHorário: Seg-Sex, 9h-18h'
|
|
979
|
+
});
|
|
980
|
+
break;
|
|
981
|
+
|
|
982
|
+
case 'about':
|
|
983
|
+
await whatsapp.send_text({
|
|
984
|
+
to: sender,
|
|
985
|
+
message: 'ℹ️ *Sobre Nós*\n\nSomos uma empresa especializada em tecnologia desde 2020.\n\nMissão: Levar tecnologia de qualidade a todos.'
|
|
986
|
+
});
|
|
987
|
+
break;
|
|
988
|
+
|
|
989
|
+
case 'cat_smartphones':
|
|
990
|
+
await whatsapp.send_text({
|
|
991
|
+
to: sender,
|
|
992
|
+
message: '📱 *Smartphones*\n\n1. iPhone 14 Pro - R$ 7.999\n2. Samsung S23 - R$ 5.499\n3. Xiaomi 13 - R$ 3.999\n\nPara mais info, digite o número do produto.'
|
|
993
|
+
});
|
|
994
|
+
break;
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
```
|
|
998
|
+
|
|
999
|
+
---
|
|
1000
|
+
|
|
1001
|
+
## ✅ Best Practices
|
|
1002
|
+
|
|
1003
|
+
### 1. Tratamento de Erros Robusto
|
|
1004
|
+
|
|
1005
|
+
```typescript
|
|
1006
|
+
async function sendMessageSafely(to: string, message: string) {
|
|
1007
|
+
try {
|
|
1008
|
+
const whatsapp = sdk.Message.WhatsappResponse({
|
|
1009
|
+
companyId: 'abc123',
|
|
1010
|
+
phone_number_id: '123456789012345'
|
|
1011
|
+
});
|
|
1012
|
+
|
|
1013
|
+
const result = await whatsapp.send_text({ to, message });
|
|
1014
|
+
|
|
1015
|
+
if (result.isLeft()) {
|
|
1016
|
+
// Log estruturado
|
|
1017
|
+
console.error('Erro ao enviar mensagem:', {
|
|
1018
|
+
to,
|
|
1019
|
+
error: result.value,
|
|
1020
|
+
timestamp: new Date().toISOString()
|
|
1021
|
+
});
|
|
1022
|
+
|
|
1023
|
+
// Alertar equipe (ex: Slack, email)
|
|
1024
|
+
await notifyTeam(`Falha no envio para ${to}`);
|
|
1025
|
+
|
|
1026
|
+
return false;
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
return true;
|
|
1030
|
+
} catch (error) {
|
|
1031
|
+
console.error('Exceção não tratada:', error);
|
|
1032
|
+
return false;
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
```
|
|
1036
|
+
|
|
1037
|
+
### 2. Rate Limiting
|
|
1038
|
+
|
|
1039
|
+
```typescript
|
|
1040
|
+
import PQueue from 'p-queue';
|
|
1041
|
+
|
|
1042
|
+
// Fila com limite
|
|
1043
|
+
const messageQueue = new PQueue({
|
|
1044
|
+
interval: 1000, // 1 segundo
|
|
1045
|
+
intervalCap: 10 // 10 mensagens por segundo
|
|
1046
|
+
});
|
|
1047
|
+
|
|
1048
|
+
async function sendWithQueue(to: string, message: string) {
|
|
1049
|
+
return messageQueue.add(() =>
|
|
1050
|
+
whatsapp.send_text({ to, message })
|
|
1051
|
+
);
|
|
1052
|
+
}
|
|
1053
|
+
```
|
|
1054
|
+
|
|
1055
|
+
### 3. Timeout para Webhooks
|
|
1056
|
+
|
|
1057
|
+
```typescript
|
|
1058
|
+
sdk.on('message', async (data) => {
|
|
1059
|
+
// Responder imediatamente à Meta (evitar timeout de 15s)
|
|
1060
|
+
setImmediate(async () => {
|
|
1061
|
+
try {
|
|
1062
|
+
await processMessageAsync(data);
|
|
1063
|
+
} catch (error) {
|
|
1064
|
+
console.error('Erro no processamento:', error);
|
|
1065
|
+
}
|
|
1066
|
+
});
|
|
1067
|
+
});
|
|
1068
|
+
|
|
1069
|
+
async function processMessageAsync(data: any) {
|
|
1070
|
+
// Processamento demorado aqui
|
|
1071
|
+
const analysis = await deepAnalysis(data.message);
|
|
1072
|
+
await sendResponse(data.sender, analysis);
|
|
1073
|
+
}
|
|
1074
|
+
```
|
|
1075
|
+
|
|
1076
|
+
### 4. Logging Estruturado
|
|
1077
|
+
|
|
1078
|
+
```typescript
|
|
1079
|
+
import winston from 'winston';
|
|
1080
|
+
|
|
1081
|
+
const logger = winston.createLogger({
|
|
1082
|
+
level: 'info',
|
|
1083
|
+
format: winston.format.json(),
|
|
1084
|
+
transports: [
|
|
1085
|
+
new winston.transports.File({ filename: 'error.log', level: 'error' }),
|
|
1086
|
+
new winston.transports.File({ filename: 'combined.log' })
|
|
1087
|
+
]
|
|
1088
|
+
});
|
|
1089
|
+
|
|
1090
|
+
sdk.on('message', (data) => {
|
|
1091
|
+
logger.info('message_received', {
|
|
1092
|
+
sender: data.sender,
|
|
1093
|
+
type: data.message.type,
|
|
1094
|
+
timestamp: new Date().toISOString()
|
|
1095
|
+
});
|
|
1096
|
+
});
|
|
1097
|
+
```
|
|
1098
|
+
|
|
1099
|
+
### 5. Validação de Números
|
|
1100
|
+
|
|
1101
|
+
```typescript
|
|
1102
|
+
import { parsePhoneNumber } from 'libphonenumber-js';
|
|
1103
|
+
|
|
1104
|
+
function validateAndFormatPhone(phone: string, countryCode: string = 'BR'): string | null {
|
|
1105
|
+
try {
|
|
1106
|
+
const phoneNumber = parsePhoneNumber(phone, countryCode);
|
|
1107
|
+
if (phoneNumber.isValid()) {
|
|
1108
|
+
return phoneNumber.format('E.164'); // +5511999999999
|
|
1109
|
+
}
|
|
1110
|
+
} catch (error) {
|
|
1111
|
+
console.error('Número inválido:', phone);
|
|
1112
|
+
}
|
|
1113
|
+
return null;
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
// Uso
|
|
1117
|
+
const formattedPhone = validateAndFormatPhone('11999999999', 'BR');
|
|
1118
|
+
if (formattedPhone) {
|
|
1119
|
+
await whatsapp.send_text({ to: formattedPhone, message: 'Olá!' });
|
|
1120
|
+
}
|
|
1121
|
+
```
|
|
1122
|
+
|
|
1123
|
+
---
|
|
1124
|
+
|
|
1125
|
+
## 🔗 Próximos Passos
|
|
1126
|
+
|
|
1127
|
+
- **[Troubleshooting](08-troubleshooting.md)** - Resolva problemas comuns
|
|
1128
|
+
- **[Integrações](05-integracoes.md)** - Aprofunde-se nas APIs
|
|
1129
|
+
- **[Fluxos Funcionais](04-fluxos-funcionais.md)** - Entenda os processos internos
|
|
1130
|
+
|
|
1131
|
+
---
|
|
1132
|
+
|
|
1133
|
+
[⬅️ Anterior: Entidades](06-entidades.md) | [⬆️ Voltar ao Índice](README.md) | [➡️ Próximo: Troubleshooting](08-troubleshooting.md)
|