# ðŸ“‹ DOCUMENTACIÃ“N COMPLETA - API WhatsApp Business
## GuÃ­a para desarrollo de Backend Node.js

---

## ðŸŽ¯ DESCRIPCIÃ“N GENERAL

Esta es una API REST para gestionar envÃ­o de mensajes de WhatsApp Business usando la Cloud API de Meta. Permite autenticaciÃ³n, consulta de plantillas, envÃ­o individual y masivo de mensajes con seguimiento de estados.

### **URL BASE DE LA API**
```
https://apiwhats.artechsolutions-ec.com/api/api.php
```

### **CaracterÃ­sticas principales:**
- âœ… AutenticaciÃ³n por token JWT-like
- âœ… CORS habilitado (permite llamadas desde cualquier origen)
- âœ… Endpoints RESTful
- âœ… Soporte JSON
- âœ… IntegraciÃ³n con WhatsApp Cloud API (Meta)
- âœ… Tracking de estados de mensajes

---

## ðŸ” AUTENTICACIÃ“N

### **Credenciales actuales (prototipo):**
```javascript
const AUTH = {
  username: 'demo',
  password: 'demo123',
  token: 'token-prototipo-123'
}
```

### **Flujo de autenticaciÃ³n:**
1. Hacer login con usuario/contraseÃ±a â†’ Obtener token
2. Usar el token en todas las peticiones subsiguientes

---

## ðŸ“¡ ENDPOINTS DISPONIBLES

### **1. LOGIN - AutenticaciÃ³n**

**Endpoint:** `?action=login`  
**MÃ©todo:** `POST`  
**Headers:**
```http
Content-Type: application/json
```

**Body (JSON):**
```json
{
  "user": "demo",
  "pass": "demo123"
}
```

**Respuesta exitosa (200):**
```json
{
  "token": "token-prototipo-123",
  "user": "demo"
}
```

**Respuesta error (401):**
```json
{
  "error": "Credenciales invÃ¡lidas"
}
```

---

### **2. DASHBOARD - EstadÃ­sticas del sistema**

**Endpoint:** `?action=dashboard`  
**MÃ©todo:** `GET` o `POST`  
**AutenticaciÃ³n:** âœ… Requerida

**Headers:**
```http
Content-Type: application/json
Authorization: Bearer token-prototipo-123
```

O enviar token como parÃ¡metro:
```
?action=dashboard&token=token-prototipo-123
```

**Respuesta exitosa (200):**
```json
{
  "total_enviados": 150,
  "total_mes": 1250,
  "entregados_hoy": 145,
  "leidos_hoy": 120,
  "fallidos_hoy": 5,
  "costo_mes": 12.50,
  "tasa_entrega": 96.7,
  "template_mas_usado": "bienvenida_cuenta_activa"
}
```

**ExplicaciÃ³n de campos:**
- `total_enviados`: Mensajes enviados HOY
- `total_mes`: Mensajes enviados en el MES actual
- `entregados_hoy`: Mensajes con estado "delivered" hoy
- `leidos_hoy`: Mensajes con estado "read" hoy
- `fallidos_hoy`: Mensajes con estado "failed" hoy
- `costo_mes`: Costo total en USD del mes actual
- `tasa_entrega`: Porcentaje de entrega exitosa (%)
- `template_mas_usado`: Nombre de la plantilla mÃ¡s usada hoy

**Respuesta error (401):**
```json
{
  "error": "Token invÃ¡lido"
}
```

---

### **3. TEMPLATES - Listar plantillas aprobadas**

**Endpoint:** `?action=templates`  
**MÃ©todo:** `GET` o `POST`  
**AutenticaciÃ³n:** âœ… Requerida

**Headers:**
```http
Content-Type: application/json
Authorization: Bearer token-prototipo-123
```

**Respuesta exitosa (200):**
```json
[
  {
    "id": "mensaje_prueba",
    "nombre": "mensaje_prueba",
    "body": "Este es el espacio del texto",
    "variables": [],
    "requiere_media": false,
    "tipo_media": "",
    "num_variables": 0
  },
  {
    "id": "bienvenida_cuenta_activa",
    "nombre": "bienvenida_cuenta_activa",
    "body": "Hola {{1}}, Â¡bienvenido(a) a Artech Solutions!\nTe confirmamos que tu cuenta asociada al correo {{2}} estÃ¡ activa y lista para usar.\nSi no reconoces este registro, contÃ¡ctanos de inmediato.",
    "variables": [
      {
        "key": "1",
        "nombre": "nombre",
        "tipo": "text"
      },
      {
        "key": "2",
        "nombre": "correo",
        "tipo": "text"
      }
    ],
    "requiere_media": false,
    "tipo_media": "",
    "num_variables": 2
  },
  {
    "id": "facturacion_electronica_demo_v1",
    "nombre": "facturacion_electronica_demo_v1",
    "body": "Hola {{1}}ðŸ‘‹\n\nImpulsa tu negocio con facturaciÃ³n electrÃ³nica...",
    "variables": [
      {
        "key": "1",
        "nombre": "nombre_cliente",
        "tipo": "text"
      }
    ],
    "requiere_media": true,
    "tipo_media": "image",
    "num_variables": 1
  }
]
```

**ExplicaciÃ³n de campos:**
- `id`: Identificador Ãºnico de la plantilla (usar para envÃ­os)
- `nombre`: Nombre descriptivo de la plantilla
- `body`: Texto del cuerpo del mensaje (con variables {{1}}, {{2}}, etc.)
- `variables`: Array de variables que acepta la plantilla
  - `key`: Llave para enviar en params (puede ser nÃºmero "1" o nombre)
  - `nombre`: Nombre descriptivo de la variable
  - `tipo`: Tipo de dato (generalmente "text")
- `requiere_media`: Si necesita archivo multimedia (imagen/video/documento)
- `tipo_media`: Tipo de media requerida: "image", "video", "document" o ""
- `num_variables`: Cantidad de variables requeridas

---

### **4. SEND_INDIVIDUAL - Enviar mensaje individual**

**Endpoint:** `?action=send_individual`  
**MÃ©todo:** `POST`  
**AutenticaciÃ³n:** âœ… Requerida

**Headers:**
```http
Content-Type: application/json
Authorization: Bearer token-prototipo-123
```

**Body (JSON) - Ejemplo 1: Sin variables**
```json
{
  "telefono": "593998205053",
  "template_id": "mensaje_prueba",
  "params": {}
}
```

**Body (JSON) - Ejemplo 2: Con variables**
```json
{
  "telefono": "593998205053",
  "template_id": "bienvenida_cuenta_activa",
  "params": {
    "1": "Juan PÃ©rez",
    "2": "juan@example.com"
  }
}
```

**Body (JSON) - Ejemplo 3: Con media (imagen) y variables**
```json
{
  "telefono": "593998205053",
  "template_id": "facturacion_electronica_demo_v1",
  "params": {
    "1": "AndrÃ©s",
    "header_media_url": "https://tudominio.com/images/promo.jpg"
  }
}
```

**Respuesta exitosa (200):**
```json
{
  "success": true,
  "message_id": 42,
  "wamid": "wamid.HBgNNTkzOTk4MjA1MDUzFQIAERgSMkEzRjRBOEMyNTdEOTc4N0I4AA==",
  "message": "Mensaje enviado correctamente"
}
```

**Respuesta error (400):**
```json
{
  "success": false,
  "message": "Formato de telÃ©fono invÃ¡lido"
}
```

**Respuesta error (400) - Falta parÃ¡metro:**
```json
{
  "success": false,
  "message": "Falta valor para el parÃ¡metro 'nombre' (clave: 1)"
}
```

**ExplicaciÃ³n de campos:**
- `telefono`: NÃºmero en formato E.164 (ej: 593998205053 para Ecuador)
  - **IMPORTANTE:** Sin "+" y sin espacios
  - Formato: [cÃ³digo paÃ­s][nÃºmero sin 0]
  - Ecuador: 593 + 9 dÃ­gitos (593998205053)
  - Colombia: 57 + 10 dÃ­gitos
  - USA: 1 + 10 dÃ­gitos
- `template_id`: ID de la plantilla (obtenido del endpoint templates)
- `params`: Objeto con las variables requeridas
  - Si la plantilla tiene variables {{1}}, {{2}}, usar keys "1", "2"
  - Si requiere media, incluir "header_media_url" con URL pÃºblica del archivo
- `message_id`: ID interno del mensaje en la BD
- `wamid`: ID Ãºnico de WhatsApp para el mensaje

---

### **5. SEND_BULK - EnvÃ­o masivo de mensajes**

**Endpoint:** `?action=send_bulk`  
**MÃ©todo:** `POST`  
**AutenticaciÃ³n:** âœ… Requerida

**Headers:**
```http
Content-Type: application/json
Authorization: Bearer token-prototipo-123
```

**Body (JSON):**
```json
{
  "template_id": "bienvenida_cuenta_activa",
  "destinatarios": [
    {
      "telefono": "593998205053",
      "params": {
        "1": "Juan PÃ©rez",
        "2": "juan@example.com"
      }
    },
    {
      "telefono": "593987654321",
      "params": {
        "1": "MarÃ­a GarcÃ­a",
        "2": "maria@example.com"
      }
    },
    {
      "telefono": "593912345678",
      "params": {
        "1": "Pedro LÃ³pez",
        "2": "pedro@example.com"
      }
    }
  ]
}
```

**Respuesta exitosa (200):**
```json
[
  {
    "telefono": "593998205053",
    "resultado": {
      "success": true,
      "message_id": 43,
      "wamid": "wamid.HBgNNTkzOTk4MjA1MDUzFQIAERgSMkEzRjRBOEMyNTdEOTc4N0I4AA==",
      "message": "Mensaje enviado correctamente"
    }
  },
  {
    "telefono": "593987654321",
    "resultado": {
      "success": true,
      "message_id": 44,
      "wamid": "wamid.ABgNNTk3ODc2NTQzMjFGQIAERgSMkEzRjRBOEMyNTdEOTc4N0I4BB==",
      "message": "Mensaje enviado correctamente"
    }
  },
  {
    "telefono": "593912345678",
    "resultado": {
      "success": false,
      "message": "Formato de telÃ©fono invÃ¡lido"
    }
  }
]
```

**ExplicaciÃ³n:**
- EnvÃ­a el mismo template a mÃºltiples destinatarios
- Cada destinatario puede tener parÃ¡metros personalizados
- Retorna un array con el resultado individual de cada envÃ­o
- Los envÃ­os son secuenciales (no paralelos)

---

## ðŸ”§ IMPLEMENTACIÃ“N EN NODE.JS

### **Stack recomendado:**
```json
{
  "dependencies": {
    "express": "^4.18.2",
    "axios": "^1.6.0",
    "dotenv": "^16.3.1",
    "cors": "^2.8.5"
  }
}
```

### **Estructura de carpetas sugerida:**
```
node-whatsapp-api/
â”œâ”€â”€ src/
â”‚   â”œâ”€â”€ config/
â”‚   â”‚   â””â”€â”€ api.config.js       // ConfiguraciÃ³n de API externa
â”‚   â”œâ”€â”€ controllers/
â”‚   â”‚   â”œâ”€â”€ auth.controller.js  // Login
â”‚   â”‚   â”œâ”€â”€ dashboard.controller.js
â”‚   â”‚   â”œâ”€â”€ templates.controller.js
â”‚   â”‚   â””â”€â”€ messages.controller.js
â”‚   â”œâ”€â”€ services/
â”‚   â”‚   â””â”€â”€ whatsapp.service.js // Consumo de API externa
â”‚   â”œâ”€â”€ routes/
â”‚   â”‚   â””â”€â”€ api.routes.js       // Rutas de tu backend
â”‚   â”œâ”€â”€ middleware/
â”‚   â”‚   â””â”€â”€ auth.middleware.js  // ValidaciÃ³n de tokens
â”‚   â””â”€â”€ app.js                   // Express app
â”œâ”€â”€ .env
â”œâ”€â”€ package.json
â””â”€â”€ README.md
```

---

### **1. Archivo de configuraciÃ³n (`src/config/api.config.js`)**

```javascript
module.exports = {
  // URL base de la API PHP
  API_BASE_URL: process.env.API_BASE_URL || 'https://apiwhats.artechsolutions-ec.com/api/api.php',
  
  // Credenciales de autenticaciÃ³n
  API_USERNAME: process.env.API_USERNAME || 'demo',
  API_PASSWORD: process.env.API_PASSWORD || 'demo123',
  
  // Token (se obtiene dinÃ¡micamente, pero hay uno fijo de respaldo)
  API_TOKEN: process.env.API_TOKEN || 'token-prototipo-123',
  
  // Timeout para peticiones
  REQUEST_TIMEOUT: 30000,
  
  // Puerto de tu servidor Node
  PORT: process.env.PORT || 3000
};
```

---

### **2. Servicio de WhatsApp (`src/services/whatsapp.service.js`)**

```javascript
const axios = require('axios');
const config = require('../config/api.config');

class WhatsAppService {
  constructor() {
    this.baseURL = config.API_BASE_URL;
    this.token = null;
    
    // Cliente axios con configuraciÃ³n base
    this.client = axios.create({
      baseURL: this.baseURL,
      timeout: config.REQUEST_TIMEOUT,
      headers: {
        'Content-Type': 'application/json'
      }
    });
  }

  /**
   * Login y obtenciÃ³n de token
   */
  async login() {
    try {
      const response = await this.client.post('', {
        user: config.API_USERNAME,
        pass: config.API_PASSWORD
      }, {
        params: { action: 'login' }
      });
      
      this.token = response.data.token;
      return {
        success: true,
        token: this.token,
        user: response.data.user
      };
    } catch (error) {
      return {
        success: false,
        message: error.response?.data?.error || 'Error en login'
      };
    }
  }

  /**
   * Asegurar que tenemos token vÃ¡lido
   */
  async ensureAuthenticated() {
    if (!this.token) {
      const result = await this.login();
      if (!result.success) {
        throw new Error('No se pudo autenticar con la API');
      }
    }
  }

  /**
   * Obtener estadÃ­sticas del dashboard
   */
  async getDashboard() {
    await this.ensureAuthenticated();
    
    try {
      const response = await this.client.get('', {
        params: { 
          action: 'dashboard',
          token: this.token 
        }
      });
      
      return {
        success: true,
        data: response.data
      };
    } catch (error) {
      return {
        success: false,
        message: error.response?.data?.error || 'Error obteniendo dashboard'
      };
    }
  }

  /**
   * Listar plantillas aprobadas
   */
  async getTemplates() {
    await this.ensureAuthenticated();
    
    try {
      const response = await this.client.get('', {
        params: { 
          action: 'templates',
          token: this.token 
        }
      });
      
      return {
        success: true,
        data: response.data
      };
    } catch (error) {
      return {
        success: false,
        message: error.response?.data?.error || 'Error obteniendo plantillas'
      };
    }
  }

  /**
   * Enviar mensaje individual
   * @param {string} telefono - NÃºmero en formato E.164 (ej: 593998205053)
   * @param {string} templateId - ID de la plantilla
   * @param {object} params - ParÃ¡metros de la plantilla
   */
  async sendIndividual(telefono, templateId, params = {}) {
    await this.ensureAuthenticated();
    
    try {
      const response = await this.client.post('', {
        telefono,
        template_id: templateId,
        params
      }, {
        params: { 
          action: 'send_individual',
          token: this.token 
        }
      });
      
      return response.data;
    } catch (error) {
      return {
        success: false,
        message: error.response?.data?.message || 'Error enviando mensaje'
      };
    }
  }

  /**
   * Enviar mensajes masivos
   * @param {string} templateId - ID de la plantilla
   * @param {Array} destinatarios - Array de {telefono, params}
   */
  async sendBulk(templateId, destinatarios) {
    await this.ensureAuthenticated();
    
    try {
      const response = await this.client.post('', {
        template_id: templateId,
        destinatarios
      }, {
        params: { 
          action: 'send_bulk',
          token: this.token 
        }
      });
      
      return {
        success: true,
        data: response.data
      };
    } catch (error) {
      return {
        success: false,
        message: error.response?.data?.error || 'Error en envÃ­o masivo'
      };
    }
  }
}

module.exports = new WhatsAppService();
```

---

### **3. Controladores de ejemplo**

#### **Dashboard Controller (`src/controllers/dashboard.controller.js`)**

```javascript
const whatsappService = require('../services/whatsapp.service');

exports.getStats = async (req, res) => {
  try {
    const result = await whatsappService.getDashboard();
    
    if (!result.success) {
      return res.status(400).json({
        error: result.message
      });
    }
    
    res.json({
      success: true,
      stats: result.data
    });
  } catch (error) {
    res.status(500).json({
      error: 'Error interno del servidor',
      details: error.message
    });
  }
};
```

#### **Templates Controller (`src/controllers/templates.controller.js`)**

```javascript
const whatsappService = require('../services/whatsapp.service');

exports.listTemplates = async (req, res) => {
  try {
    const result = await whatsappService.getTemplates();
    
    if (!result.success) {
      return res.status(400).json({
        error: result.message
      });
    }
    
    res.json({
      success: true,
      templates: result.data,
      total: result.data.length
    });
  } catch (error) {
    res.status(500).json({
      error: 'Error interno del servidor',
      details: error.message
    });
  }
};

exports.getTemplateById = async (req, res) => {
  try {
    const { id } = req.params;
    const result = await whatsappService.getTemplates();
    
    if (!result.success) {
      return res.status(400).json({
        error: result.message
      });
    }
    
    const template = result.data.find(t => t.id === id);
    
    if (!template) {
      return res.status(404).json({
        error: 'Plantilla no encontrada'
      });
    }
    
    res.json({
      success: true,
      template
    });
  } catch (error) {
    res.status(500).json({
      error: 'Error interno del servidor',
      details: error.message
    });
  }
};
```

#### **Messages Controller (`src/controllers/messages.controller.js`)**

```javascript
const whatsappService = require('../services/whatsapp.service');

/**
 * Enviar mensaje individual
 */
exports.sendSingle = async (req, res) => {
  try {
    const { telefono, template_id, params } = req.body;
    
    // Validaciones
    if (!telefono || !template_id) {
      return res.status(400).json({
        error: 'Faltan campos requeridos: telefono, template_id'
      });
    }
    
    // Validar formato de telÃ©fono (Ecuador)
    if (!telefono.match(/^593\d{9}$/)) {
      return res.status(400).json({
        error: 'Formato de telÃ©fono invÃ¡lido. Debe ser: 593XXXXXXXXX'
      });
    }
    
    const result = await whatsappService.sendIndividual(
      telefono,
      template_id,
      params || {}
    );
    
    if (!result.success) {
      return res.status(400).json({
        error: result.message
      });
    }
    
    res.json({
      success: true,
      message: 'Mensaje enviado correctamente',
      data: result
    });
  } catch (error) {
    res.status(500).json({
      error: 'Error interno del servidor',
      details: error.message
    });
  }
};

/**
 * Enviar mensajes masivos
 */
exports.sendBulk = async (req, res) => {
  try {
    const { template_id, destinatarios } = req.body;
    
    // Validaciones
    if (!template_id || !Array.isArray(destinatarios) || destinatarios.length === 0) {
      return res.status(400).json({
        error: 'Faltan campos requeridos o formato invÃ¡lido'
      });
    }
    
    const result = await whatsappService.sendBulk(
      template_id,
      destinatarios
    );
    
    if (!result.success) {
      return res.status(400).json({
        error: result.message
      });
    }
    
    // Analizar resultados
    const exitosos = result.data.filter(r => r.resultado.success).length;
    const fallidos = result.data.length - exitosos;
    
    res.json({
      success: true,
      message: `EnvÃ­o masivo completado: ${exitosos} exitosos, ${fallidos} fallidos`,
      summary: {
        total: result.data.length,
        exitosos,
        fallidos
      },
      detalles: result.data
    });
  } catch (error) {
    res.status(500).json({
      error: 'Error interno del servidor',
      details: error.message
    });
  }
};
```

---

### **4. Rutas (`src/routes/api.routes.js`)**

```javascript
const express = require('express');
const router = express.Router();

const dashboardController = require('../controllers/dashboard.controller');
const templatesController = require('../controllers/templates.controller');
const messagesController = require('../controllers/messages.controller');

// Dashboard
router.get('/dashboard', dashboardController.getStats);

// Templates
router.get('/templates', templatesController.listTemplates);
router.get('/templates/:id', templatesController.getTemplateById);

// Messages
router.post('/messages/send', messagesController.sendSingle);
router.post('/messages/bulk', messagesController.sendBulk);

module.exports = router;
```

---

### **5. AplicaciÃ³n principal (`src/app.js`)**

```javascript
const express = require('express');
const cors = require('cors');
require('dotenv').config();

const apiRoutes = require('./routes/api.routes');
const config = require('./config/api.config');

const app = express();

// Middleware
app.use(cors());
app.use(express.json());
app.use(express.urlencoded({ extended: true }));

// Logging simple
app.use((req, res, next) => {
  console.log(`${new Date().toISOString()} - ${req.method} ${req.path}`);
  next();
});

// Rutas
app.use('/api', apiRoutes);

// Ruta de health check
app.get('/', (req, res) => {
  res.json({
    service: 'WhatsApp API Node.js Backend',
    version: '1.0.0',
    status: 'running'
  });
});

// Manejo de errores 404
app.use((req, res) => {
  res.status(404).json({
    error: 'Endpoint no encontrado'
  });
});

// Manejo de errores generales
app.use((err, req, res, next) => {
  console.error(err.stack);
  res.status(500).json({
    error: 'Error interno del servidor',
    message: err.message
  });
});

// Iniciar servidor
const PORT = config.PORT;
app.listen(PORT, () => {
  console.log(`ðŸš€ Servidor escuchando en puerto ${PORT}`);
  console.log(`ðŸ“¡ API Externa: ${config.API_BASE_URL}`);
});

module.exports = app;
```

---

### **6. Archivo .env**

```env
# API Externa (PHP)
API_BASE_URL=https://apiwhats.artechsolutions-ec.com/api/api.php
API_USERNAME=demo
API_PASSWORD=demo123
API_TOKEN=token-prototipo-123

# Servidor Node
PORT=3000
NODE_ENV=development
```

---

### **7. Package.json**

```json
{
  "name": "whatsapp-node-backend",
  "version": "1.0.0",
  "description": "Backend Node.js para consumir API WhatsApp Business",
  "main": "src/app.js",
  "scripts": {
    "start": "node src/app.js",
    "dev": "nodemon src/app.js"
  },
  "keywords": ["whatsapp", "api", "node", "express"],
  "author": "Tu Nombre",
  "license": "MIT",
  "dependencies": {
    "express": "^4.18.2",
    "axios": "^1.6.0",
    "dotenv": "^16.3.1",
    "cors": "^2.8.5"
  },
  "devDependencies": {
    "nodemon": "^3.0.2"
  }
}
```

---

## ðŸ“® PRUEBAS CON POSTMAN

### **ColecciÃ³n de Postman (Importar este JSON):**

```json
{
  "info": {
    "name": "WhatsApp API Node Backend",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "item": [
    {
      "name": "Health Check",
      "request": {
        "method": "GET",
        "header": [],
        "url": {
          "raw": "http://localhost:3000/",
          "protocol": "http",
          "host": ["localhost"],
          "port": "3000",
          "path": [""]
        }
      }
    },
    {
      "name": "Get Dashboard Stats",
      "request": {
        "method": "GET",
        "header": [],
        "url": {
          "raw": "http://localhost:3000/api/dashboard",
          "protocol": "http",
          "host": ["localhost"],
          "port": "3000",
          "path": ["api", "dashboard"]
        }
      }
    },
    {
      "name": "List Templates",
      "request": {
        "method": "GET",
        "header": [],
        "url": {
          "raw": "http://localhost:3000/api/templates",
          "protocol": "http",
          "host": ["localhost"],
          "port": "3000",
          "path": ["api", "templates"]
        }
      }
    },
    {
      "name": "Get Template by ID",
      "request": {
        "method": "GET",
        "header": [],
        "url": {
          "raw": "http://localhost:3000/api/templates/mensaje_prueba",
          "protocol": "http",
          "host": ["localhost"],
          "port": "3000",
          "path": ["api", "templates", "mensaje_prueba"]
        }
      }
    },
    {
      "name": "Send Single Message (No params)",
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ],
        "body": {
          "mode": "raw",
          "raw": "{\n  \"telefono\": \"593998205053\",\n  \"template_id\": \"mensaje_prueba\",\n  \"params\": {}\n}"
        },
        "url": {
          "raw": "http://localhost:3000/api/messages/send",
          "protocol": "http",
          "host": ["localhost"],
          "port": "3000",
          "path": ["api", "messages", "send"]
        }
      }
    },
    {
      "name": "Send Single Message (With params)",
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ],
        "body": {
          "mode": "raw",
          "raw": "{\n  \"telefono\": \"593998205053\",\n  \"template_id\": \"bienvenida_cuenta_activa\",\n  \"params\": {\n    \"1\": \"Juan PÃ©rez\",\n    \"2\": \"juan@example.com\"\n  }\n}"
        },
        "url": {
          "raw": "http://localhost:3000/api/messages/send",
          "protocol": "http",
          "host": ["localhost"],
          "port": "3000",
          "path": ["api", "messages", "send"]
        }
      }
    },
    {
      "name": "Send Single Message (With image)",
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ],
        "body": {
          "mode": "raw",
          "raw": "{\n  \"telefono\": \"593998205053\",\n  \"template_id\": \"facturacion_electronica_demo_v1\",\n  \"params\": {\n    \"1\": \"AndrÃ©s\",\n    \"header_media_url\": \"https://ejemplo.com/imagen.jpg\"\n  }\n}"
        },
        "url": {
          "raw": "http://localhost:3000/api/messages/send",
          "protocol": "http",
          "host": ["localhost"],
          "port": "3000",
          "path": ["api", "messages", "send"]
        }
      }
    },
    {
      "name": "Send Bulk Messages",
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ],
        "body": {
          "mode": "raw",
          "raw": "{\n  \"template_id\": \"bienvenida_cuenta_activa\",\n  \"destinatarios\": [\n    {\n      \"telefono\": \"593998205053\",\n      \"params\": {\n        \"1\": \"Juan PÃ©rez\",\n        \"2\": \"juan@example.com\"\n      }\n    },\n    {\n      \"telefono\": \"593987654321\",\n      \"params\": {\n        \"1\": \"MarÃ­a GarcÃ­a\",\n        \"2\": \"maria@example.com\"\n      }\n    }\n  ]\n}"
        },
        "url": {
          "raw": "http://localhost:3000/api/messages/bulk",
          "protocol": "http",
          "host": ["localhost"],
          "port": "3000",
          "path": ["api", "messages", "bulk"]
        }
      }
    }
  ]
}
```

---

## ðŸŽ¯ EJEMPLOS DE USO ESPECÃFICOS

### **Ejemplo 1: Enviar mensaje simple (sin parÃ¡metros)**

```bash
curl -X POST http://localhost:3000/api/messages/send \
  -H "Content-Type: application/json" \
  -d '{
    "telefono": "593998205053",
    "template_id": "mensaje_prueba",
    "params": {}
  }'
```

### **Ejemplo 2: Enviar mensaje de bienvenida con parÃ¡metros**

```bash
curl -X POST http://localhost:3000/api/messages/send \
  -H "Content-Type: application/json" \
  -d '{
    "telefono": "593998205053",
    "template_id": "bienvenida_cuenta_activa",
    "params": {
      "1": "Juan PÃ©rez",
      "2": "juan@example.com"
    }
  }'
```

### **Ejemplo 3: Enviar mensaje con imagen**

```bash
curl -X POST http://localhost:3000/api/messages/send \
  -H "Content-Type: application/json" \
  -d '{
    "telefono": "593998205053",
    "template_id": "facturacion_electronica_demo_v1",
    "params": {
      "1": "AndrÃ©s",
      "header_media_url": "https://tudominio.com/promo.jpg"
    }
  }'
```

### **Ejemplo 4: EnvÃ­o masivo a 3 personas**

```bash
curl -X POST http://localhost:3000/api/messages/bulk \
  -H "Content-Type: application/json" \
  -d '{
    "template_id": "bienvenida_cuenta_activa",
    "destinatarios": [
      {
        "telefono": "593998205053",
        "params": {"1": "Juan", "2": "juan@mail.com"}
      },
      {
        "telefono": "593987654321",
        "params": {"1": "MarÃ­a", "2": "maria@mail.com"}
      },
      {
        "telefono": "593912345678",
        "params": {"1": "Pedro", "2": "pedro@mail.com"}
      }
    ]
  }'
```

---

## ðŸ“Š ESTRUCTURA DE BASE DE DATOS (Referencia)

### **Tabla: messages**
Almacena todos los mensajes enviados.

```sql
CREATE TABLE messages (
  id BIGINT PRIMARY KEY AUTO_INCREMENT,
  to_e164 VARCHAR(20) NOT NULL,
  template_name VARCHAR(100) NOT NULL,
  category ENUM('marketing','utility','authentication','service'),
  phone_number_id VARCHAR(50),
  wa_message_id VARCHAR(255) UNIQUE,
  sent_at TIMESTAMP
);
```

### **Tabla: message_status**
Rastrea los estados de los mensajes (sent, delivered, read, failed).

```sql
CREATE TABLE message_status (
  id BIGINT PRIMARY KEY AUTO_INCREMENT,
  message_id BIGINT NOT NULL,
  status ENUM('sent','delivered','read','failed') NOT NULL,
  error_code VARCHAR(40),
  error_title VARCHAR(120),
  error_detail VARCHAR(255),
  ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  UNIQUE KEY (message_id, status, ts)
);
```

### **Tabla: whatsapp_templates**
Plantillas aprobadas por Meta.

```sql
CREATE TABLE whatsapp_templates (
  id INT PRIMARY KEY AUTO_INCREMENT,
  template_id VARCHAR(50) UNIQUE NOT NULL,
  name VARCHAR(100) NOT NULL,
  status ENUM('PENDING','APPROVED','REJECTED','PAUSED','DISABLED'),
  category ENUM('MARKETING','UTILITY','AUTHENTICATION','TRANSACTIONAL'),
  language VARCHAR(10) DEFAULT 'es',
  body_text TEXT NOT NULL,
  variable_count INT DEFAULT 0,
  components JSON
);
```

---

## âš ï¸ CONSIDERACIONES IMPORTANTES

### **1. Formato de telÃ©fonos:**
- **SIEMPRE** usar formato E.164 sin "+"
- Ecuador: `593` + 9 dÃ­gitos â†’ `593998205053`
- Colombia: `57` + 10 dÃ­gitos â†’ `573001234567`
- MÃ©xico: `52` + 10 dÃ­gitos â†’ `525512345678`
- USA: `1` + 10 dÃ­gitos â†’ `15551234567`

### **2. Variables de plantillas:**
- Las variables se identifican con `{{1}}`, `{{2}}`, etc. en el texto
- Al enviar, usar las keys "1", "2", etc. en el objeto `params`
- **TODAS las variables son obligatorias**

### **3. Media (imÃ¡genes/videos/documentos):**
- Solo se pueden usar con plantillas que lo requieran
- La URL debe ser pÃºblica y accesible desde Internet
- Formatos soportados:
  - **Imagen:** JPG, PNG (mÃ¡x 5MB)
  - **Video:** MP4, 3GP (mÃ¡x 16MB)
  - **Documento:** PDF (mÃ¡x 100MB)
- Enviar en `params` con key `header_media_url`

### **4. LÃ­mites de Meta:**
- MÃ¡ximo 1,000 mensajes por segundo por nÃºmero
- Plantillas deben estar aprobadas por Meta
- Solo se pueden enviar plantillas (no mensajes libres)
- Los destinatarios deben haber aceptado recibir mensajes

### **5. CategorÃ­as de plantillas:**
- **MARKETING:** Promociones, ofertas (costo mÃ¡s alto)
- **UTILITY:** Notificaciones transaccionales (costo medio)
- **AUTHENTICATION:** CÃ³digos OTP, verificaciÃ³n (costo bajo)

### **6. Seguimiento de estados:**
Los mensajes pasan por estos estados:
1. `sent` - Enviado a WhatsApp
2. `delivered` - Entregado al dispositivo
3. `read` - LeÃ­do por el usuario
4. `failed` - Error en el envÃ­o

---

## ðŸš€ COMANDOS PARA INICIAR

```bash
# 1. Crear proyecto
mkdir whatsapp-node-backend
cd whatsapp-node-backend

# 2. Inicializar npm
npm init -y

# 3. Instalar dependencias
npm install express axios dotenv cors
npm install --save-dev nodemon

# 4. Crear estructura (copiar archivos arriba)
mkdir -p src/{config,controllers,services,routes,middleware}

# 5. Crear .env con tus datos

# 6. Ejecutar en desarrollo
npm run dev

# 7. O en producciÃ³n
npm start
```

---

## ðŸ§ª ORDEN DE PRUEBAS RECOMENDADO

1. **Health Check** â†’ Verificar que el servidor Node estÃ© corriendo
2. **Dashboard** â†’ Probar conexiÃ³n con API externa
3. **List Templates** â†’ Ver plantillas disponibles
4. **Get Template by ID** â†’ Verificar detalles de una plantilla
5. **Send Single (sin params)** â†’ Enviar plantilla simple
6. **Send Single (con params)** â†’ Enviar con variables
7. **Send Single (con imagen)** â†’ Enviar con media
8. **Send Bulk** â†’ EnvÃ­o masivo

---

## ðŸ“ NOTAS ADICIONALES

### **Errores comunes y soluciones:**

**Error: "Token invÃ¡lido"**
- SoluciÃ³n: El servicio renovarÃ¡ automÃ¡ticamente el token

**Error: "Formato de telÃ©fono invÃ¡lido"**
- SoluciÃ³n: Usar formato E.164 sin "+" (ej: 593998205053)

**Error: "Falta valor para el parÃ¡metro"**
- SoluciÃ³n: Verificar que se envÃ­en todas las variables requeridas

**Error: "Plantilla no vÃ¡lida o no aprobada"**
- SoluciÃ³n: Usar solo plantillas con status APPROVED

**Error: CORS**
- SoluciÃ³n: Ya estÃ¡ habilitado en la API PHP y en Node

---

## ðŸŽ BONUS: Endpoint adicional para webhooks

Si quieres recibir notificaciones de estados de mensajes:

```javascript
// En routes/api.routes.js
router.post('/webhooks/status', async (req, res) => {
  const { message_id, status, timestamp } = req.body;
  
  console.log(`Mensaje ${message_id} cambiÃ³ a estado: ${status}`);
  
  // AquÃ­ puedes guardar en tu propia BD o procesar
  
  res.status(200).send('OK');
});
```

---

## ðŸ“§ SOPORTE

Para dudas o problemas con la API PHP original, contactar al equipo de Artech Solutions.

---

**Fin de la documentaciÃ³n. Â¡Suerte con el desarrollo! ðŸš€**


---

##  ENDPOINTS DE REPORTES (NUEVO)

### **6. REPORTS - Sistema de reportería completa**

**Endpoint:** `?action=reports`  
**Método:** `GET` o `POST`  
**Autenticación:**  Requerida

Este endpoint unificado maneja 5 tipos diferentes de reportes. La API retorna datos en JSON para que el backend Node.js los procese y genere archivos Excel según sea necesario.

---

### **TIPOS DE REPORTES DISPONIBLES:**

#### **6.1. Reporte Detallado** (`type=detallado`)

**Descripción:** Todos los mensajes con estados, tiempos de entrega/lectura y costos

**Parámetros:**
- `type`: `detallado` (requerido)
- `from`: Fecha inicio (YYYY-MM-DD) (requerido)
- `to`: Fecha fin (YYYY-MM-DD) (requerido)
- `token`: Token de autenticación (requerido)

**Ejemplo de petición:**
```
GET https://apiwhats.artechsolutions-ec.com/api/api.php?action=reports&type=detallado&from=2026-01-04&to=2026-02-03&token=token-prototipo-123
```

**Respuesta JSON:**
```json
{
  "success": true,
  "type": "detallado",
  "fecha_inicio": "2026-01-04",
  "fecha_fin": "2026-02-03",
  "total_registros": 150,
  "resumen": {
    "total_enviados": 150,
    "total_entregados": 145,
    "total_leidos": 120,
    "total_fallidos": 5,
    "costo_total": "0.75",
    "tasa_entrega": 96.67,
    "tasa_lectura": 80
  },
  "data": [
    {
      "id": 42,
      "fecha_envio": "2026-01-04 10:30:00",
      "telefono": "593998205053",
      "template": "bienvenida_cuenta_activa",
      "categoria": "utility",
      "estado_actual": "read",
      "tiempo_entrega": "2s",
      "tiempo_lectura": "1m 30s",
      "costo": "0.00500",
      "wamid": "wamid.HBgNNTkzOTk4MjA1MDUzFQIAERgSMkEzRjRBOEMyNTdEOTc4N0I4AA=="
    }
  ]
}
```

---

#### **6.2. Reporte Resumen** (`type=resumen`)

**Descripción:** Datos agrupados por fecha, plantilla y categoría

**Parámetros:**
- `type`: `resumen` (requerido)
- `from`: Fecha inicio (YYYY-MM-DD) (requerido)
- `to`: Fecha fin (YYYY-MM-DD) (requerido)
- `token`: Token de autenticación (requerido)

**Ejemplo de petición:**
```
GET https://apiwhats.artechsolutions-ec.com/api/api.php?action=reports&type=resumen&from=2026-01-04&to=2026-02-03&token=token-prototipo-123
```

**Respuesta JSON:**
```json
{
  "success": true,
  "type": "resumen",
  "fecha_inicio": "2026-01-04",
  "fecha_fin": "2026-02-03",
  "total_registros": 25,
  "resumen": {
    "total_enviados": 150,
    "total_entregados": 145,
    "total_leidos": 120,
    "total_fallidos": 5,
    "costo_total": "0.75"
  },
  "data": [
    {
      "fecha": "2026-02-03",
      "template": "bienvenida_cuenta_activa",
      "categoria": "utility",
      "total_enviados": 50,
      "total_entregados": 48,
      "total_leidos": 45,
      "total_fallidos": 2,
      "costo_total": "0.25"
    }
  ]
}
```

---

#### **6.3. Reporte de Errores** (`type=errores`)

**Descripción:** Análisis de errores y números problemáticos (histórico completo)

**Parámetros:**
- `type`: `errores` (requerido)
- `token`: Token de autenticación (requerido)
-  **NO requiere fechas** (analiza todo el histórico)

**Ejemplo de petición:**
```
GET https://apiwhats.artechsolutions-ec.com/api/api.php?action=reports&type=errores&token=token-prototipo-123
```

**Respuesta JSON:**
```json
{
  "success": true,
  "type": "errores",
  "fecha_inicio": "",
  "fecha_fin": "",
  "total_registros": 12,
  "resumen": {
    "total_numeros_problematicos": 12,
    "total_fallos_acumulados": 45
  },
  "data": [
    {
      "telefono": "593912345678",
      "total_intentos": 10,
      "total_fallidos": 10,
      "ultimo_error_codigo": "131049",
      "ultimo_error_mensaje": "This message was not delivered to maintain healthy ecosystem engagement.",
      "primera_falla": "2026-01-15",
      "ultima_falla": "2026-02-01"
    }
  ]
}
```

---

#### **6.4. Reporte de Conversaciones** (`type=conversaciones`)

**Descripción:** Mensajes enviados y respuestas recibidas por contacto

**Parámetros:**
- `type`: `conversaciones` (requerido)
- `from`: Fecha inicio (YYYY-MM-DD) (requerido)
- `to`: Fecha fin (YYYY-MM-DD) (requerido)
- `token`: Token de autenticación (requerido)

**Ejemplo de petición:**
```
GET https://apiwhats.artechsolutions-ec.com/api/api.php?action=reports&type=conversaciones&from=2026-01-04&to=2026-02-03&token=token-prototipo-123
```

**Respuesta JSON:**
```json
{
  "success": true,
  "type": "conversaciones",
  "fecha_inicio": "2026-01-04",
  "fecha_fin": "2026-02-03",
  "total_registros": 85,
  "resumen": {
    "total_contactos": 85,
    "total_mensajes_enviados": 150,
    "total_mensajes_recibidos": 120,
    "contactos_con_respuesta": 80
  },
  "data": [
    {
      "telefono": "593998205053",
      "mensajes_enviados": 3,
      "mensajes_recibidos": 5,
      "ultimo_mensaje_enviado": "2026-02-01 10:30:00",
      "ultimo_mensaje_recibido": "2026-02-01 14:25:00",
      "estado_conversacion": "activa"
    }
  ]
}
```

---

#### **6.5. Reporte de Mensajes Entrantes** (`type=entrantes`)

**Descripción:** Solo respuestas y mensajes recibidos de clientes

**Parámetros:**
- `type`: `entrantes` (requerido)
- `from`: Fecha inicio (YYYY-MM-DD) (requerido)
- `to`: Fecha fin (YYYY-MM-DD) (requerido)
- `token`: Token de autenticación (requerido)

**Ejemplo de petición:**
```
GET https://apiwhats.artechsolutions-ec.com/api/api.php?action=reports&type=entrantes&from=2026-01-04&to=2026-02-03&token=token-prototipo-123
```

**Respuesta JSON:**
```json
{
  "success": true,
  "type": "entrantes",
  "fecha_inicio": "2026-01-04",
  "fecha_fin": "2026-02-03",
  "total_registros": 120,
  "resumen": {
    "total_mensajes_entrantes": 120,
    "por_tipo": {
      "text": 110,
      "image": 8,
      "audio": 2
    }
  },
  "data": [
    {
      "id": 523,
      "fecha": "2026-02-01 14:25:00",
      "telefono": "593998205053",
      "tipo_mensaje": "text",
      "contenido": "Gracias por la información",
      "wamid": "wamid.ABgNNTk3ODc2NTQzMjFGQIAERgSMkEzRjRBOEMyNTdEOTc4N0I4BB==",
      "respondiendo_a": "wamid.HBgNNTkzOTk4MjA1MDUzFQIAERgSMkEzRjRBOEMyNTdEOTc4N0I4AA=="
    }
  ]
}
```

---

##  IMPLEMENTACIÓN NODE.JS - SERVICIOS DE REPORTES

### **Servicio de Reportes (`src/services/reports.service.js`)**

```javascript
const axios = require('axios');
const ExcelJS = require('exceljs');
const config = require('../config/api.config');

class ReportsService {
  constructor() {
    this.baseURL = config.API_BASE_URL;
    this.token = config.API_TOKEN;
  }

  /**
   * Obtener datos de reporte en JSON
   */
  async getReportData(type, from, to) {
    try {
      const params = {
        action: 'reports',
        type: type,
        token: this.token
      };

      // Agregar fechas solo si el tipo las requiere
      if (type !== 'errores') {
        if (!from || !to) {
          throw new Error('Fechas requeridas para este tipo de reporte');
        }
        params.from = from;
        params.to = to;
      }

      const response = await axios.get(this.baseURL, { params });

      return {
        success: true,
        data: response.data
      };
    } catch (error) {
      return {
        success: false,
        message: error.response?.data?.error || error.message
      };
    }
  }

  /**
   * Generar Excel desde datos JSON
   */
  async generateExcel(type, from, to) {
    try {
      // 1. Obtener datos
      const result = await this.getReportData(type, from, to);
      if (!result.success) {
        throw new Error(result.message);
      }

      const reportData = result.data;

      // 2. Crear workbook
      const workbook = new ExcelJS.Workbook();
      const worksheet = workbook.addWorksheet('Reporte');

      // 3. Configurar según tipo de reporte
      switch(type) {
        case 'detallado':
          this.setupDetalladoSheet(worksheet, reportData);
          break;
        case 'resumen':
          this.setupResumenSheet(worksheet, reportData);
          break;
        case 'errores':
          this.setupErroresSheet(worksheet, reportData);
          break;
        case 'conversaciones':
          this.setupConversacionesSheet(worksheet, reportData);
          break;
        case 'entrantes':
          this.setupEntrantesSheet(worksheet, reportData);
          break;
      }

      // 4. Generar buffer
      const buffer = await workbook.xlsx.writeBuffer();
      return buffer;

    } catch (error) {
      throw new Error('Error generando Excel: ' + error.message);
    }
  }

  setupDetalladoSheet(worksheet, reportData) {
    // Título
    worksheet.mergeCells('A1:J1');
    worksheet.getCell('A1').value = 'Reporte Detallado de Mensajes';
    worksheet.getCell('A1').font = { size: 16, bold: true };
    worksheet.getCell('A1').alignment = { horizontal: 'center' };

    // Resumen
    worksheet.getCell('A3').value = `Total Enviados: \`;
    worksheet.getCell('A4').value = `Total Entregados: \`;
    worksheet.getCell('A5').value = `Costo Total: $\`;

    // Encabezados
    worksheet.getRow(7).values = [
      'ID', 'Fecha Envío', 'Teléfono', 'Template', 'Categoría',
      'Estado', 'Tiempo Entrega', 'Tiempo Lectura', 'Costo', 'WAMID'
    ];
    worksheet.getRow(7).font = { bold: true };
    worksheet.getRow(7).fill = {
      type: 'pattern',
      pattern: 'solid',
      fgColor: { argb: 'FF4CAF50' }
    };

    // Datos
    reportData.data.forEach((row, index) => {
      worksheet.addRow([
        row.id,
        row.fecha_envio,
        row.telefono,
        row.template,
        row.categoria,
        row.estado_actual,
        row.tiempo_entrega,
        row.tiempo_lectura,
        row.costo,
        row.wamid
      ]);
    });

    // Auto-ajustar columnas
    worksheet.columns.forEach(column => {
      column.width = 15;
    });
  }

  setupResumenSheet(worksheet, reportData) {
    // Similar al anterior pero con columnas diferentes
    worksheet.mergeCells('A1:H1');
    worksheet.getCell('A1').value = 'Reporte Resumen';
    worksheet.getCell('A1').font = { size: 16, bold: true };
    worksheet.getCell('A1').alignment = { horizontal: 'center' };

    worksheet.getRow(3).values = [
      'Fecha', 'Template', 'Categoría', 'Enviados',
      'Entregados', 'Leídos', 'Fallidos', 'Costo Total'
    ];
    worksheet.getRow(3).font = { bold: true };
    worksheet.getRow(3).fill = {
      type: 'pattern',
      pattern: 'solid',
      fgColor: { argb: 'FF2196F3' }
    };

    reportData.data.forEach(row => {
      worksheet.addRow([
        row.fecha,
        row.template,
        row.categoria,
        row.total_enviados,
        row.total_entregados,
        row.total_leidos,
        row.total_fallidos,
        row.costo_total
      ]);
    });

    worksheet.columns.forEach(column => {
      column.width = 15;
    });
  }

  setupErroresSheet(worksheet, reportData) {
    worksheet.mergeCells('A1:G1');
    worksheet.getCell('A1').value = 'Reporte de Errores';
    worksheet.getCell('A1').font = { size: 16, bold: true };
    worksheet.getCell('A1').alignment = { horizontal: 'center' };

    worksheet.getRow(3).values = [
      'Teléfono', 'Intentos', 'Fallidos', 'Código Error',
      'Mensaje Error', 'Primera Falla', 'Última Falla'
    ];
    worksheet.getRow(3).font = { bold: true };
    worksheet.getRow(3).fill = {
      type: 'pattern',
      pattern: 'solid',
      fgColor: { argb: 'FFF44336' }
    };

    reportData.data.forEach(row => {
      worksheet.addRow([
        row.telefono,
        row.total_intentos,
        row.total_fallidos,
        row.ultimo_error_codigo,
        row.ultimo_error_mensaje,
        row.primera_falla,
        row.ultima_falla
      ]);
    });

    worksheet.columns.forEach(column => {
      column.width = 20;
    });
  }

  setupConversacionesSheet(worksheet, reportData) {
    worksheet.mergeCells('A1:F1');
    worksheet.getCell('A1').value = 'Reporte de Conversaciones';
    worksheet.getCell('A1').font = { size: 16, bold: true };
    worksheet.getCell('A1').alignment = { horizontal: 'center' };

    worksheet.getRow(3).values = [
      'Teléfono', 'Enviados', 'Recibidos',
      'Último Enviado', 'Último Recibido', 'Estado'
    ];
    worksheet.getRow(3).font = { bold: true };
    worksheet.getRow(3).fill = {
      type: 'pattern',
      pattern: 'solid',
      fgColor: { argb: 'FF9C27B0' }
    };

    reportData.data.forEach(row => {
      worksheet.addRow([
        row.telefono,
        row.mensajes_enviados,
        row.mensajes_recibidos,
        row.ultimo_mensaje_enviado,
        row.ultimo_mensaje_recibido,
        row.estado_conversacion
      ]);
    });

    worksheet.columns.forEach(column => {
      column.width = 18;
    });
  }

  setupEntrantesSheet(worksheet, reportData) {
    worksheet.mergeCells('A1:F1');
    worksheet.getCell('A1').value = 'Reporte de Mensajes Entrantes';
    worksheet.getCell('A1').font = { size: 16, bold: true };
    worksheet.getCell('A1').alignment = { horizontal: 'center' };

    worksheet.getRow(3).values = [
      'ID', 'Fecha', 'Teléfono', 'Tipo', 'Contenido', 'WAMID'
    ];
    worksheet.getRow(3).font = { bold: true };
    worksheet.getRow(3).fill = {
      type: 'pattern',
      pattern: 'solid',
      fgColor: { argb: 'FFFF9800' }
    };

    reportData.data.forEach(row => {
      worksheet.addRow([
        row.id,
        row.fecha,
        row.telefono,
        row.tipo_mensaje,
        row.contenido,
        row.wamid
      ]);
    });

    worksheet.columns.forEach(column => {
      column.width = 15;
    });
    worksheet.getColumn(5).width = 30; // Contenido más ancho
  }
}

module.exports = new ReportsService();
```

---

### **Controlador de Reportes (`src/controllers/reports.controller.js`)**

```javascript
const reportsService = require('../services/reports.service');

/**
 * Obtener datos de reporte en JSON
 */
exports.getReportData = async (req, res) => {
  try {
    const { type } = req.params;
    const { from, to } = req.query;

    const result = await reportsService.getReportData(type, from, to);

    if (!result.success) {
      return res.status(400).json({
        error: result.message
      });
    }

    res.json(result.data);
  } catch (error) {
    res.status(500).json({
      error: 'Error interno del servidor',
      details: error.message
    });
  }
};

/**
 * Descargar reporte en Excel
 */
exports.downloadExcel = async (req, res) => {
  try {
    const { type } = req.params;
    const { from, to } = req.query;

    const buffer = await reportsService.generateExcel(type, from, to);

    const filename = `reporte_\_\_\.xlsx`;

    res.setHeader('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
    res.setHeader('Content-Disposition', `attachment; filename=\`);
    res.send(buffer);

  } catch (error) {
    res.status(500).json({
      error: 'Error generando Excel',
      details: error.message
    });
  }
};
```

---

### **Rutas de Reportes (agregar a `src/routes/api.routes.js`)**

```javascript
const reportsController = require('../controllers/reports.controller');

// Reportes - Obtener datos JSON
router.get('/reports/:type', reportsController.getReportData);

// Reportes - Descargar Excel
router.get('/reports/:type/export', reportsController.downloadExcel);
```

---

##  PRUEBAS CON POSTMAN/CURL

### **Obtener datos de Reporte Detallado:**
```bash
curl "https://apiwhats.artechsolutions-ec.com/api/api.php?action=reports&type=detallado&from=2026-01-04&to=2026-02-03&token=token-prototipo-123"
```

### **Obtener Reporte de Errores (sin fechas):**
```bash
curl "https://apiwhats.artechsolutions-ec.com/api/api.php?action=reports&type=errores&token=token-prototipo-123"
```

### **Desde el backend Node.js - Obtener JSON:**
```bash
curl "http://localhost:3000/api/reports/detallado?from=2026-01-04&to=2026-02-03"
```

### **Desde el backend Node.js - Descargar Excel:**
```bash
curl "http://localhost:3000/api/reports/detallado/export?from=2026-01-04&to=2026-02-03" --output reporte.xlsx
```

---

##  DEPENDENCIAS ADICIONALES PARA NODE.JS

Actualiza tu `package.json`:

```json
{
  "dependencies": {
    "express": "^4.18.2",
    "axios": "^1.6.0",
    "dotenv": "^16.3.1",
    "cors": "^2.8.5",
    "exceljs": "^4.4.0"
  }
}
```

Instalar:
```bash
npm install exceljs
```

---

##  RESUMEN DE ENDPOINTS DE REPORTES

| Tipo | Endpoint | Fechas Requeridas | Descripción |
|------|----------|-------------------|-------------|
| `detallado` | `?action=reports&type=detallado` |  Sí | Todos los mensajes con detalle completo |
| `resumen` | `?action=reports&type=resumen` |  Sí | Agrupado por fecha/plantilla/categoría |
| `errores` | `?action=reports&type=errores` |  No | Números problemáticos (histórico) |
| `conversaciones` | `?action=reports&type=conversaciones` |  Sí | Enviados y recibidos por contacto |
| `entrantes` | `?action=reports&type=entrantes` |  Sí | Solo mensajes recibidos de clientes |

---

**¡Sistema de reportería completo implementado!** 
