Files
whatsappNucleo/README.md
josedario87 a848adf4f8
All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 1m9s
Fix: Preservar alias al recargar lista de chats
El endpoint chats.get no retornaba el campo alias, lo que causaba
que al recargar los chats (cuando llega un mensaje nuevo) el alias
se perdiera.

Cambios:
- Agregar alias a la query de chats.get
- Priorizar alias sobre name en la respuesta
- Incluir originalName para referencia en el modal
2025-12-04 16:04:47 -06:00

533 lines
13 KiB
Markdown

# WhatsApp Nucleo
Sistema de gestión centralizada de múltiples instancias de WhatsApp para Nucleo V3.
## MCP Server para Claude Code
Agregar el MCP a tu proyecto (usa tu NUXT_MASTER_API_KEY):
```bash
claude mcp add --transport http whatsapp https://whatsapp.nucleoriofrio.com/api/mcp --header "Authorization: Bearer <NUXT_MASTER_API_KEY>"
```
---
## Setup
```bash
npm install
```
## Development
```bash
npm run dev
```
## Production
```bash
npm run build
node .output/server/index.mjs
```
---
## API REST
### Autenticación
Todos los endpoints requieren autenticación mediante API Key:
```
Authorization: Bearer <NUXT_MASTER_API_KEY>
```
### Instancias
| Método | Endpoint | Descripción |
|--------|----------|-------------|
| GET | `/api/instances` | Listar todas las instancias |
| POST | `/api/instances` | Crear nueva instancia |
| GET | `/api/instances/:id` | Obtener detalles de instancia |
| GET | `/api/instances/:id/qr` | Obtener código QR |
| POST | `/api/instances/:id/connect` | Conectar instancia |
| POST | `/api/instances/:id/disconnect` | Desconectar instancia |
| DELETE | `/api/instances/:id` | Eliminar instancia |
**Ejemplo - Listar instancias:**
```bash
curl -X GET "https://whatsapp.nucleoriofrio.com/api/instances" \
-H "Authorization: Bearer <API_KEY>"
```
**Ejemplo - Crear instancia:**
```bash
curl -X POST "https://whatsapp.nucleoriofrio.com/api/instances" \
-H "Authorization: Bearer <API_KEY>" \
-H "Content-Type: application/json" \
-d '{"name": "Mi WhatsApp"}'
```
### Obtener Lista de Chats/Contactos
```
GET /api/messages/:instanceId/chats
```
Retorna todos los chats (contactos individuales y grupos) de una instancia, ordenados por última actividad.
**Ejemplo:**
```bash
curl -X GET "https://whatsapp.nucleoriofrio.com/api/messages/{instanceId}/chats" \
-H "Authorization: Bearer <API_KEY>"
```
**Respuesta:**
```json
[
{
"id": "chat_abc123",
"jid": "5491155551234@s.whatsapp.net",
"name": "Juan Pérez",
"isGroup": false,
"unreadCount": 2,
"lastMessageAt": "2025-01-15T10:30:00Z",
"lastMessage": "Hola, ¿cómo estás?",
"lastMessageType": "text"
},
{
"id": "chat_xyz789",
"jid": "120363123456789012@g.us",
"name": "Grupo de Trabajo",
"isGroup": true,
"unreadCount": 0,
"lastMessageAt": "2025-01-15T09:00:00Z",
"lastMessage": "Reunión a las 3pm",
"lastMessageType": "text"
}
]
```
**Campos de respuesta:**
| Campo | Tipo | Descripción |
|-------|------|-------------|
| `id` | string | ID interno del chat (usar en otros endpoints) |
| `jid` | string | JID de WhatsApp del contacto/grupo |
| `name` | string | Nombre del contacto o grupo |
| `isGroup` | boolean | `true` si es un grupo |
| `unreadCount` | number | Cantidad de mensajes no leídos |
| `lastMessageAt` | string | Fecha ISO del último mensaje |
| `lastMessage` | string | Contenido del último mensaje |
| `lastMessageType` | string | Tipo del último mensaje |
---
### Obtener Mensajes de un Chat
```
GET /api/messages/:instanceId/:chatId
```
Obtiene los mensajes de un chat con soporte para paginación.
**Parámetros de Query:**
| Parámetro | Tipo | Default | Descripción |
|-----------|------|---------|-------------|
| `limit` | number | 50 | Cantidad de mensajes (máx: 100) |
| `offset` | number | 0 | Saltar N mensajes |
| `before` | string | - | Timestamp ISO para scroll infinito |
**Ejemplo - Obtener últimos 50 mensajes:**
```bash
curl -X GET "https://whatsapp.nucleoriofrio.com/api/messages/{instanceId}/{chatId}" \
-H "Authorization: Bearer <API_KEY>"
```
**Ejemplo - Paginación con limit/offset:**
```bash
curl -X GET "https://whatsapp.nucleoriofrio.com/api/messages/{instanceId}/{chatId}?limit=20&offset=40" \
-H "Authorization: Bearer <API_KEY>"
```
**Ejemplo - Scroll infinito (mensajes antes de fecha):**
```bash
curl -X GET "https://whatsapp.nucleoriofrio.com/api/messages/{instanceId}/{chatId}?limit=20&before=2025-01-15T10:00:00Z" \
-H "Authorization: Bearer <API_KEY>"
```
**Respuesta:**
```json
[
{
"id": "msg_123",
"messageId": "3EB0A1B2C3D4E5F6",
"chatId": "chat_abc123",
"fromJid": "5491155551234@s.whatsapp.net",
"fromMe": false,
"type": "text",
"content": "Hola, ¿cómo estás?",
"caption": null,
"media": null,
"timestamp": "2025-01-15T10:30:00Z",
"status": "read",
"pushName": "Juan",
"isGroup": false
},
{
"id": "msg_124",
"messageId": "3EB0A1B2C3D4E5F7",
"chatId": "chat_abc123",
"fromJid": "me",
"fromMe": true,
"type": "image",
"content": null,
"caption": "Mira esta foto",
"media": {
"mimetype": "image/jpeg",
"filesize": 245000,
"width": 1920,
"height": 1080,
"thumbnail": "base64..."
},
"timestamp": "2025-01-15T10:31:00Z",
"status": "delivered",
"isGroup": false
}
]
```
**Campos de respuesta por tipo:**
| Campo | Descripción |
|-------|-------------|
| `messageId` | ID de WhatsApp (usar para reaccionar o citar) |
| `fromMe` | `true` si lo envié yo |
| `type` | text, image, video, audio, document, sticker, contact, location, poll, event |
| `content` | Texto del mensaje |
| `caption` | Caption de media |
| `media` | Info de archivo (mimetype, filesize, thumbnail, etc.) |
| `poll` | Datos de encuesta (name, options, selectableCount) |
| `event` | Datos de evento (name, startDate, location) |
| `quoted` | Mensaje citado (id, content, type) |
| `pushName` | Nombre del remitente |
| `participant` | JID del participante (en grupos) |
---
### Enviar Mensajes
```
POST /api/messages/:instanceId/:chatId/send
```
Endpoint unificado para enviar todos los tipos de mensaje. El tipo se detecta automáticamente según el Content-Type y body.
#### Mensaje de Texto
```bash
curl -X POST "https://whatsapp.nucleoriofrio.com/api/messages/{instanceId}/{chatId}/send" \
-H "Authorization: Bearer <API_KEY>" \
-H "Content-Type: application/json" \
-d '{
"content": "Hola! Este es un mensaje de texto"
}'
```
**Con mensaje citado:**
```bash
curl -X POST "https://whatsapp.nucleoriofrio.com/api/messages/{instanceId}/{chatId}/send" \
-H "Authorization: Bearer <API_KEY>" \
-H "Content-Type: application/json" \
-d '{
"content": "Esta es mi respuesta",
"quotedMessageId": "3EB0A1B2C3D4E5F6"
}'
```
#### Imagen
```bash
curl -X POST "https://whatsapp.nucleoriofrio.com/api/messages/{instanceId}/{chatId}/send" \
-H "Authorization: Bearer <API_KEY>" \
-F "file=@foto.jpg" \
-F "caption=Descripción de la imagen"
```
#### Video
```bash
curl -X POST "https://whatsapp.nucleoriofrio.com/api/messages/{instanceId}/{chatId}/send" \
-H "Authorization: Bearer <API_KEY>" \
-F "file=@video.mp4" \
-F "caption=Mi video"
```
#### Audio / Nota de Voz
```bash
# Audio normal
curl -X POST "https://whatsapp.nucleoriofrio.com/api/messages/{instanceId}/{chatId}/send" \
-H "Authorization: Bearer <API_KEY>" \
-F "file=@audio.mp3"
# Nota de voz (PTT - Push To Talk)
curl -X POST "https://whatsapp.nucleoriofrio.com/api/messages/{instanceId}/{chatId}/send" \
-H "Authorization: Bearer <API_KEY>" \
-F "file=@nota.ogg" \
-F "isPtt=true"
```
#### Documento
```bash
curl -X POST "https://whatsapp.nucleoriofrio.com/api/messages/{instanceId}/{chatId}/send" \
-H "Authorization: Bearer <API_KEY>" \
-F "file=@reporte.pdf" \
-F "caption=Reporte mensual de ventas"
```
#### Sticker
```bash
curl -X POST "https://whatsapp.nucleoriofrio.com/api/messages/{instanceId}/{chatId}/send" \
-H "Authorization: Bearer <API_KEY>" \
-F "file=@imagen.png" \
-F 'asSticker=["true"]'
```
> Se convierte automáticamente a WebP. Formatos soportados: JPG, PNG, WebP.
#### Contacto
```bash
curl -X POST "https://whatsapp.nucleoriofrio.com/api/messages/{instanceId}/{chatId}/send" \
-H "Authorization: Bearer <API_KEY>" \
-H "Content-Type: application/json" \
-d '{
"type": "contact",
"contacts": [
{
"displayName": "Juan Pérez",
"phoneNumber": "+5491155551234",
"organization": "Empresa SA"
}
]
}'
```
**Múltiples contactos:**
```bash
curl -X POST "https://whatsapp.nucleoriofrio.com/api/messages/{instanceId}/{chatId}/send" \
-H "Authorization: Bearer <API_KEY>" \
-H "Content-Type: application/json" \
-d '{
"type": "contact",
"contacts": [
{"displayName": "Juan", "phoneNumber": "+5491155551234"},
{"displayName": "María", "phoneNumber": "+5491166662345"}
]
}'
```
#### Encuesta (Poll)
```bash
curl -X POST "https://whatsapp.nucleoriofrio.com/api/messages/{instanceId}/{chatId}/send" \
-H "Authorization: Bearer <API_KEY>" \
-H "Content-Type: application/json" \
-d '{
"type": "poll",
"name": "¿Qué día prefieres para la reunión?",
"options": ["Lunes", "Martes", "Miércoles", "Jueves", "Viernes"],
"selectableCount": 1
}'
```
**Parámetros de Poll:**
| Campo | Requerido | Descripción |
|-------|-----------|-------------|
| `name` | Sí | Pregunta de la encuesta |
| `options` | Sí | Array de opciones (mín: 2, máx: 12) |
| `selectableCount` | No | Cuántas opciones se pueden elegir (default: 1) |
#### Evento
```bash
curl -X POST "https://whatsapp.nucleoriofrio.com/api/messages/{instanceId}/{chatId}/send" \
-H "Authorization: Bearer <API_KEY>" \
-H "Content-Type: application/json" \
-d '{
"type": "event",
"name": "Reunión de equipo",
"startDate": "2025-01-20T14:00:00Z",
"endDate": "2025-01-20T15:00:00Z",
"description": "Revisión semanal del proyecto",
"location": {
"name": "Oficina Central",
"address": "Av. Corrientes 1234, CABA",
"latitude": -34.6037,
"longitude": -58.3816
}
}'
```
**Parámetros de Event:**
| Campo | Requerido | Descripción |
|-------|-----------|-------------|
| `name` | Sí | Nombre del evento |
| `startDate` | Sí | Fecha/hora inicio (ISO 8601) |
| `endDate` | No | Fecha/hora fin |
| `description` | No | Descripción del evento |
| `location.name` | No | Nombre del lugar |
| `location.address` | No | Dirección |
| `location.latitude` | No | Latitud |
| `location.longitude` | No | Longitud |
**Respuesta de envío (todos los tipos):**
```json
{
"success": true,
"messages": [
{
"messageId": "3EB0A1B2C3D4E5F6",
"type": "text"
}
]
}
```
---
### Responder/Citar Mensajes (quotedMessageId)
Todos los tipos de mensaje soportan citar otro mensaje usando `quotedMessageId`. El mensaje citado aparece como "respuesta a" en WhatsApp.
**Texto citando otro mensaje:**
```bash
curl -X POST "https://whatsapp.nucleoriofrio.com/api/messages/{instanceId}/{chatId}/send" \
-H "Authorization: Bearer <API_KEY>" \
-H "Content-Type: application/json" \
-d '{
"content": "Totalmente de acuerdo!",
"quotedMessageId": "3EB0A1B2C3D4E5F6"
}'
```
**Imagen citando otro mensaje:**
```bash
curl -X POST "https://whatsapp.nucleoriofrio.com/api/messages/{instanceId}/{chatId}/send" \
-H "Authorization: Bearer <API_KEY>" \
-F "file=@imagen.jpg" \
-F "caption=Mira esto!" \
-F "quotedMessageId=3EB0A1B2C3D4E5F6"
```
**Encuesta citando otro mensaje:**
```bash
curl -X POST "https://whatsapp.nucleoriofrio.com/api/messages/{instanceId}/{chatId}/send" \
-H "Authorization: Bearer <API_KEY>" \
-H "Content-Type: application/json" \
-d '{
"type": "poll",
"name": "¿Qué opinan sobre esto?",
"options": ["De acuerdo", "En desacuerdo", "Neutral"],
"quotedMessageId": "3EB0A1B2C3D4E5F6"
}'
```
> **Nota:** El `quotedMessageId` se obtiene del campo `messageId` al listar mensajes con `GET /api/messages/:instanceId/:chatId`
---
### Reaccionar a Mensajes
```
POST /api/messages/:instanceId/react
```
Envía una reacción (emoji) a un mensaje existente.
**Body:**
```json
{
"messageId": "3EB0A1B2C3D4E5F6",
"emoji": "👍"
}
```
**Ejemplo - Agregar reacción:**
```bash
curl -X POST "https://whatsapp.nucleoriofrio.com/api/messages/{instanceId}/react" \
-H "Authorization: Bearer <API_KEY>" \
-H "Content-Type: application/json" \
-d '{"messageId": "3EB0A1B2C3D4E5F6", "emoji": "👍"}'
```
**Ejemplo - Quitar reacción:**
```bash
curl -X POST "https://whatsapp.nucleoriofrio.com/api/messages/{instanceId}/react" \
-H "Authorization: Bearer <API_KEY>" \
-H "Content-Type: application/json" \
-d '{"messageId": "3EB0A1B2C3D4E5F6", "emoji": ""}'
```
**Emojis comunes:**
| Emoji | Significado |
|-------|-------------|
| 👍 | Me gusta |
| ❤️ | Amor |
| 😂 | Risa |
| 😮 | Sorpresa |
| 😢 | Tristeza |
| 🙏 | Gracias |
**Respuesta:**
```json
{
"success": true,
"messageId": "3EB0A1B2C3D4E5F6",
"emoji": "👍"
}
```
> **Nota:** El `messageId` se obtiene de la respuesta al obtener mensajes (`GET /api/messages/:instanceId/:chatId`)
### Formato de Destinatarios (JID)
- **Contacto individual:** `5491155551234@s.whatsapp.net` (código país sin +)
- **Grupo:** `123456789012345678@g.us`
### Tipos de Mensaje Soportados
| Tipo | Descripción |
|------|-------------|
| `text` | Mensaje de texto |
| `image` | Imagen con caption opcional |
| `video` | Video con caption opcional |
| `audio` | Audio o nota de voz |
| `document` | Documento/archivo |
| `sticker` | Sticker |
| `contact` | Tarjeta de contacto |
| `poll` | Encuesta (2-12 opciones) |
| `event` | Evento con fecha/ubicación |
### Límites de Archivos
| Tipo | Tamaño Máximo |
|------|---------------|
| Imagen | 16 MB |
| Video | 64 MB |
| Audio | 16 MB |
| Documento | 100 MB |
| Sticker | 500 KB |
---
## Stack
- **Frontend:** Nuxt 3, Vue 3, Nuxt UI, TailwindCSS
- **Backend:** Nitro, PostgreSQL
- **WhatsApp:** Baileys v6.7.9
- **Auth:** Authentik + Traefik