Initial commit: Documentación completa del proyecto WhatsApp Centralizado
- README principal con descripción del proyecto - Documento de diseño completo (arquitectura, DB, flujos) - Documentación de API REST y WebSocket - Guía del Flow Builder (30+ tipos de nodos) - Documentación de integración con Odoo - Guía de despliegue con Docker - Esquema de base de datos - Estructura de carpetas del proyecto - Archivo .env.example con todas las variables Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
746
docs/api/README.md
Normal file
746
docs/api/README.md
Normal file
@@ -0,0 +1,746 @@
|
||||
# API Reference
|
||||
|
||||
## Información General
|
||||
|
||||
- **Base URL:** `https://tu-dominio.com/api`
|
||||
- **Autenticación:** Bearer Token (JWT)
|
||||
- **Content-Type:** `application/json`
|
||||
|
||||
## Autenticación
|
||||
|
||||
### Login
|
||||
```http
|
||||
POST /auth/login
|
||||
```
|
||||
|
||||
**Request:**
|
||||
```json
|
||||
{
|
||||
"email": "usuario@empresa.com",
|
||||
"password": "tu_password"
|
||||
}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
|
||||
"token_type": "bearer",
|
||||
"user": {
|
||||
"id": "uuid",
|
||||
"email": "usuario@empresa.com",
|
||||
"name": "Usuario",
|
||||
"role": "admin"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Refresh Token
|
||||
```http
|
||||
POST /auth/refresh
|
||||
```
|
||||
|
||||
### Logout
|
||||
```http
|
||||
POST /auth/logout
|
||||
```
|
||||
|
||||
### Usuario Actual
|
||||
```http
|
||||
GET /auth/me
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Usuarios
|
||||
|
||||
### Listar Usuarios
|
||||
```http
|
||||
GET /api/users
|
||||
```
|
||||
|
||||
**Query Parameters:**
|
||||
| Parámetro | Tipo | Descripción |
|
||||
|-----------|------|-------------|
|
||||
| role | string | Filtrar por rol (admin, supervisor, agent) |
|
||||
| status | string | Filtrar por estado (online, offline, away) |
|
||||
| page | int | Página (default: 1) |
|
||||
| limit | int | Límite por página (default: 20) |
|
||||
|
||||
### Crear Usuario
|
||||
```http
|
||||
POST /api/users
|
||||
```
|
||||
|
||||
**Request:**
|
||||
```json
|
||||
{
|
||||
"email": "nuevo@empresa.com",
|
||||
"password": "password123",
|
||||
"name": "Nuevo Usuario",
|
||||
"role": "agent"
|
||||
}
|
||||
```
|
||||
|
||||
### Obtener Usuario
|
||||
```http
|
||||
GET /api/users/{user_id}
|
||||
```
|
||||
|
||||
### Actualizar Usuario
|
||||
```http
|
||||
PUT /api/users/{user_id}
|
||||
```
|
||||
|
||||
### Eliminar Usuario
|
||||
```http
|
||||
DELETE /api/users/{user_id}
|
||||
```
|
||||
|
||||
### Cambiar Estado
|
||||
```http
|
||||
PUT /api/users/{user_id}/status
|
||||
```
|
||||
|
||||
**Request:**
|
||||
```json
|
||||
{
|
||||
"status": "away"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Cuentas WhatsApp
|
||||
|
||||
### Listar Cuentas
|
||||
```http
|
||||
GET /api/whatsapp/accounts
|
||||
```
|
||||
|
||||
### Crear Cuenta (Iniciar conexión)
|
||||
```http
|
||||
POST /api/whatsapp/accounts
|
||||
```
|
||||
|
||||
**Request:**
|
||||
```json
|
||||
{
|
||||
"name": "Ventas Principal"
|
||||
}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"id": "uuid",
|
||||
"name": "Ventas Principal",
|
||||
"status": "disconnected",
|
||||
"qr_code": null
|
||||
}
|
||||
```
|
||||
|
||||
### Obtener QR Code
|
||||
```http
|
||||
GET /api/whatsapp/accounts/{account_id}/qr
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"qr_code": "data:image/png;base64,..."
|
||||
}
|
||||
```
|
||||
|
||||
### Estado de Cuenta
|
||||
```http
|
||||
GET /api/whatsapp/accounts/{account_id}/status
|
||||
```
|
||||
|
||||
### Desconectar Cuenta
|
||||
```http
|
||||
POST /api/whatsapp/accounts/{account_id}/disconnect
|
||||
```
|
||||
|
||||
### Reconectar Cuenta
|
||||
```http
|
||||
POST /api/whatsapp/accounts/{account_id}/reconnect
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Contactos
|
||||
|
||||
### Listar Contactos
|
||||
```http
|
||||
GET /api/contacts
|
||||
```
|
||||
|
||||
**Query Parameters:**
|
||||
| Parámetro | Tipo | Descripción |
|
||||
|-----------|------|-------------|
|
||||
| search | string | Buscar por nombre, teléfono o email |
|
||||
| tags | string[] | Filtrar por etiquetas |
|
||||
| has_odoo | boolean | Filtrar sincronizados con Odoo |
|
||||
| page | int | Página |
|
||||
| limit | int | Límite |
|
||||
|
||||
### Crear Contacto
|
||||
```http
|
||||
POST /api/contacts
|
||||
```
|
||||
|
||||
**Request:**
|
||||
```json
|
||||
{
|
||||
"phone_number": "+525551234567",
|
||||
"name": "Juan Pérez",
|
||||
"email": "juan@email.com",
|
||||
"company": "Empresa ABC",
|
||||
"tags": ["lead", "interesado"],
|
||||
"metadata": {
|
||||
"producto_interes": "Laptop Pro"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Obtener Contacto
|
||||
```http
|
||||
GET /api/contacts/{contact_id}
|
||||
```
|
||||
|
||||
### Actualizar Contacto
|
||||
```http
|
||||
PUT /api/contacts/{contact_id}
|
||||
```
|
||||
|
||||
### Agregar Etiquetas
|
||||
```http
|
||||
POST /api/contacts/{contact_id}/tags
|
||||
```
|
||||
|
||||
**Request:**
|
||||
```json
|
||||
{
|
||||
"tags": ["vip", "cliente"]
|
||||
}
|
||||
```
|
||||
|
||||
### Sincronizar con Odoo
|
||||
```http
|
||||
POST /api/contacts/{contact_id}/sync-odoo
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Conversaciones
|
||||
|
||||
### Listar Conversaciones
|
||||
```http
|
||||
GET /api/conversations
|
||||
```
|
||||
|
||||
**Query Parameters:**
|
||||
| Parámetro | Tipo | Descripción |
|
||||
|-----------|------|-------------|
|
||||
| status | string | bot, waiting, active, resolved |
|
||||
| queue_id | uuid | Filtrar por cola |
|
||||
| assigned_to | uuid | Filtrar por agente |
|
||||
| priority | string | low, normal, high, urgent |
|
||||
| page | int | Página |
|
||||
| limit | int | Límite |
|
||||
|
||||
### Obtener Conversación
|
||||
```http
|
||||
GET /api/conversations/{conversation_id}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"id": "uuid",
|
||||
"contact": {
|
||||
"id": "uuid",
|
||||
"name": "Juan Pérez",
|
||||
"phone_number": "+525551234567"
|
||||
},
|
||||
"whatsapp_account": {
|
||||
"id": "uuid",
|
||||
"name": "Ventas Principal"
|
||||
},
|
||||
"status": "active",
|
||||
"priority": "normal",
|
||||
"assigned_to": {
|
||||
"id": "uuid",
|
||||
"name": "María García"
|
||||
},
|
||||
"queue": {
|
||||
"id": "uuid",
|
||||
"name": "Ventas"
|
||||
},
|
||||
"current_flow": null,
|
||||
"sla_first_response_met": true,
|
||||
"last_message_at": "2024-01-15T14:30:00Z",
|
||||
"created_at": "2024-01-15T14:25:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
### Asignar Conversación
|
||||
```http
|
||||
POST /api/conversations/{conversation_id}/assign
|
||||
```
|
||||
|
||||
**Request:**
|
||||
```json
|
||||
{
|
||||
"user_id": "uuid"
|
||||
}
|
||||
```
|
||||
|
||||
### Transferir a Cola
|
||||
```http
|
||||
POST /api/conversations/{conversation_id}/transfer
|
||||
```
|
||||
|
||||
**Request:**
|
||||
```json
|
||||
{
|
||||
"queue_id": "uuid"
|
||||
}
|
||||
```
|
||||
|
||||
### Resolver Conversación
|
||||
```http
|
||||
POST /api/conversations/{conversation_id}/resolve
|
||||
```
|
||||
|
||||
**Request:**
|
||||
```json
|
||||
{
|
||||
"resolution_note": "Problema resuelto"
|
||||
}
|
||||
```
|
||||
|
||||
### Reabrir Conversación
|
||||
```http
|
||||
POST /api/conversations/{conversation_id}/reopen
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Mensajes
|
||||
|
||||
### Listar Mensajes de Conversación
|
||||
```http
|
||||
GET /api/conversations/{conversation_id}/messages
|
||||
```
|
||||
|
||||
**Query Parameters:**
|
||||
| Parámetro | Tipo | Descripción |
|
||||
|-----------|------|-------------|
|
||||
| before | uuid | Mensajes antes de este ID |
|
||||
| limit | int | Límite (default: 50) |
|
||||
|
||||
### Enviar Mensaje
|
||||
```http
|
||||
POST /api/conversations/{conversation_id}/messages
|
||||
```
|
||||
|
||||
**Request (texto):**
|
||||
```json
|
||||
{
|
||||
"type": "text",
|
||||
"content": "Hola, ¿en qué te puedo ayudar?"
|
||||
}
|
||||
```
|
||||
|
||||
**Request (imagen):**
|
||||
```json
|
||||
{
|
||||
"type": "image",
|
||||
"media_url": "https://example.com/image.jpg",
|
||||
"content": "Caption opcional"
|
||||
}
|
||||
```
|
||||
|
||||
**Request (botones):**
|
||||
```json
|
||||
{
|
||||
"type": "buttons",
|
||||
"content": "¿Qué necesitas?",
|
||||
"metadata": {
|
||||
"buttons": [
|
||||
{"id": "ventas", "text": "Ventas"},
|
||||
{"id": "soporte", "text": "Soporte"},
|
||||
{"id": "otro", "text": "Otro"}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Request (lista):**
|
||||
```json
|
||||
{
|
||||
"type": "list",
|
||||
"content": "Selecciona una opción:",
|
||||
"metadata": {
|
||||
"button_text": "Ver opciones",
|
||||
"sections": [
|
||||
{
|
||||
"title": "Productos",
|
||||
"rows": [
|
||||
{"id": "laptop", "title": "Laptops", "description": "Ver laptops disponibles"},
|
||||
{"id": "telefono", "title": "Teléfonos", "description": "Ver teléfonos"}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Enviar Nota Interna
|
||||
```http
|
||||
POST /api/conversations/{conversation_id}/notes
|
||||
```
|
||||
|
||||
**Request:**
|
||||
```json
|
||||
{
|
||||
"content": "Cliente interesado, dar seguimiento"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Flujos
|
||||
|
||||
### Listar Flujos
|
||||
```http
|
||||
GET /api/flows
|
||||
```
|
||||
|
||||
### Crear Flujo
|
||||
```http
|
||||
POST /api/flows
|
||||
```
|
||||
|
||||
**Request:**
|
||||
```json
|
||||
{
|
||||
"name": "Bienvenida",
|
||||
"description": "Flujo de bienvenida para nuevos contactos",
|
||||
"trigger_type": "welcome",
|
||||
"trigger_value": null,
|
||||
"nodes": {
|
||||
"nodes": [...],
|
||||
"edges": [...],
|
||||
"viewport": {...}
|
||||
},
|
||||
"is_active": true
|
||||
}
|
||||
```
|
||||
|
||||
### Obtener Flujo
|
||||
```http
|
||||
GET /api/flows/{flow_id}
|
||||
```
|
||||
|
||||
### Actualizar Flujo
|
||||
```http
|
||||
PUT /api/flows/{flow_id}
|
||||
```
|
||||
|
||||
### Duplicar Flujo
|
||||
```http
|
||||
POST /api/flows/{flow_id}/duplicate
|
||||
```
|
||||
|
||||
### Activar/Desactivar Flujo
|
||||
```http
|
||||
PUT /api/flows/{flow_id}/toggle
|
||||
```
|
||||
|
||||
### Probar Flujo
|
||||
```http
|
||||
POST /api/flows/{flow_id}/test
|
||||
```
|
||||
|
||||
**Request:**
|
||||
```json
|
||||
{
|
||||
"phone_number": "+525551234567",
|
||||
"initial_message": "Hola"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Colas
|
||||
|
||||
### Listar Colas
|
||||
```http
|
||||
GET /api/queues
|
||||
```
|
||||
|
||||
### Crear Cola
|
||||
```http
|
||||
POST /api/queues
|
||||
```
|
||||
|
||||
**Request:**
|
||||
```json
|
||||
{
|
||||
"name": "Ventas",
|
||||
"description": "Cola de atención de ventas",
|
||||
"assignment_method": "least_busy",
|
||||
"max_per_agent": 8,
|
||||
"sla_first_response": 180,
|
||||
"sla_resolution": 3600,
|
||||
"business_hours": {
|
||||
"monday": {"start": "09:00", "end": "18:00"},
|
||||
"tuesday": {"start": "09:00", "end": "18:00"},
|
||||
"wednesday": {"start": "09:00", "end": "18:00"},
|
||||
"thursday": {"start": "09:00", "end": "18:00"},
|
||||
"friday": {"start": "09:00", "end": "17:00"},
|
||||
"saturday": {"start": "10:00", "end": "14:00"},
|
||||
"sunday": null
|
||||
},
|
||||
"fallback_flow_id": "uuid"
|
||||
}
|
||||
```
|
||||
|
||||
### Obtener Cola
|
||||
```http
|
||||
GET /api/queues/{queue_id}
|
||||
```
|
||||
|
||||
### Actualizar Cola
|
||||
```http
|
||||
PUT /api/queues/{queue_id}
|
||||
```
|
||||
|
||||
### Agregar Agente a Cola
|
||||
```http
|
||||
POST /api/queues/{queue_id}/agents
|
||||
```
|
||||
|
||||
**Request:**
|
||||
```json
|
||||
{
|
||||
"user_id": "uuid",
|
||||
"is_supervisor": false,
|
||||
"skills": ["ventas", "ingles"]
|
||||
}
|
||||
```
|
||||
|
||||
### Remover Agente de Cola
|
||||
```http
|
||||
DELETE /api/queues/{queue_id}/agents/{user_id}
|
||||
```
|
||||
|
||||
### Estadísticas de Cola
|
||||
```http
|
||||
GET /api/queues/{queue_id}/stats
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"waiting": 5,
|
||||
"active": 12,
|
||||
"resolved_today": 47,
|
||||
"avg_first_response": 142,
|
||||
"avg_resolution": 1823,
|
||||
"sla_compliance": 0.91,
|
||||
"agents": [
|
||||
{
|
||||
"user_id": "uuid",
|
||||
"name": "María García",
|
||||
"status": "online",
|
||||
"active_conversations": 5,
|
||||
"resolved_today": 12
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Respuestas Rápidas
|
||||
|
||||
### Listar Respuestas Rápidas
|
||||
```http
|
||||
GET /api/quick-replies
|
||||
```
|
||||
|
||||
### Crear Respuesta Rápida
|
||||
```http
|
||||
POST /api/quick-replies
|
||||
```
|
||||
|
||||
**Request:**
|
||||
```json
|
||||
{
|
||||
"shortcut": "/saludo",
|
||||
"content": "¡Hola {{contact.name}}! Soy {{agent.name}}, ¿en qué te puedo ayudar?",
|
||||
"queue_id": null
|
||||
}
|
||||
```
|
||||
|
||||
### Actualizar Respuesta Rápida
|
||||
```http
|
||||
PUT /api/quick-replies/{id}
|
||||
```
|
||||
|
||||
### Eliminar Respuesta Rápida
|
||||
```http
|
||||
DELETE /api/quick-replies/{id}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Odoo
|
||||
|
||||
### Probar Conexión
|
||||
```http
|
||||
POST /api/odoo/test-connection
|
||||
```
|
||||
|
||||
### Sincronizar Contactos
|
||||
```http
|
||||
POST /api/odoo/sync-contacts
|
||||
```
|
||||
|
||||
### Buscar Partner
|
||||
```http
|
||||
GET /api/odoo/partners/search
|
||||
```
|
||||
|
||||
**Query Parameters:**
|
||||
| Parámetro | Tipo | Descripción |
|
||||
|-----------|------|-------------|
|
||||
| phone | string | Buscar por teléfono |
|
||||
| email | string | Buscar por email |
|
||||
| name | string | Buscar por nombre |
|
||||
|
||||
### Buscar Pedidos
|
||||
```http
|
||||
GET /api/odoo/orders
|
||||
```
|
||||
|
||||
**Query Parameters:**
|
||||
| Parámetro | Tipo | Descripción |
|
||||
|-----------|------|-------------|
|
||||
| partner_id | int | ID del partner en Odoo |
|
||||
| state | string | Estado del pedido |
|
||||
| limit | int | Límite |
|
||||
|
||||
### Consultar Stock
|
||||
```http
|
||||
GET /api/odoo/products/{product_id}/stock
|
||||
```
|
||||
|
||||
### Crear Lead
|
||||
```http
|
||||
POST /api/odoo/leads
|
||||
```
|
||||
|
||||
**Request:**
|
||||
```json
|
||||
{
|
||||
"name": "Interés en Producto X",
|
||||
"contact_name": "Juan Pérez",
|
||||
"phone": "+525551234567",
|
||||
"email": "juan@email.com",
|
||||
"description": "Cliente interesado en laptops",
|
||||
"expected_revenue": 5000
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## WebSocket
|
||||
|
||||
### Conexión
|
||||
```javascript
|
||||
const socket = io('wss://tu-dominio.com', {
|
||||
auth: {
|
||||
token: 'Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...'
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Eventos del Servidor
|
||||
|
||||
**Nuevo mensaje:**
|
||||
```javascript
|
||||
socket.on('new_message', (data) => {
|
||||
// data: { conversation_id, message }
|
||||
});
|
||||
```
|
||||
|
||||
**Estado de mensaje:**
|
||||
```javascript
|
||||
socket.on('message_status', (data) => {
|
||||
// data: { message_id, status: 'delivered' | 'read' }
|
||||
});
|
||||
```
|
||||
|
||||
**Conversación asignada:**
|
||||
```javascript
|
||||
socket.on('conversation_assigned', (data) => {
|
||||
// data: { conversation_id, assigned_to }
|
||||
});
|
||||
```
|
||||
|
||||
**QR Code:**
|
||||
```javascript
|
||||
socket.on('qr_code', (data) => {
|
||||
// data: { account_id, qr_code }
|
||||
});
|
||||
```
|
||||
|
||||
**Estado de conexión WhatsApp:**
|
||||
```javascript
|
||||
socket.on('connection_status', (data) => {
|
||||
// data: { account_id, status: 'connected' | 'disconnected' }
|
||||
});
|
||||
```
|
||||
|
||||
### Eventos del Cliente
|
||||
|
||||
**Unirse a conversación:**
|
||||
```javascript
|
||||
socket.emit('join_conversation', { conversation_id: 'uuid' });
|
||||
```
|
||||
|
||||
**Escribiendo:**
|
||||
```javascript
|
||||
socket.emit('typing', { conversation_id: 'uuid' });
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Códigos de Error
|
||||
|
||||
| Código | Descripción |
|
||||
|--------|-------------|
|
||||
| 400 | Bad Request - Datos inválidos |
|
||||
| 401 | Unauthorized - Token inválido o expirado |
|
||||
| 403 | Forbidden - Sin permisos |
|
||||
| 404 | Not Found - Recurso no encontrado |
|
||||
| 409 | Conflict - Conflicto de datos |
|
||||
| 422 | Unprocessable Entity - Validación fallida |
|
||||
| 429 | Too Many Requests - Rate limit excedido |
|
||||
| 500 | Internal Server Error |
|
||||
|
||||
**Formato de error:**
|
||||
```json
|
||||
{
|
||||
"detail": {
|
||||
"code": "VALIDATION_ERROR",
|
||||
"message": "El campo email es requerido",
|
||||
"field": "email"
|
||||
}
|
||||
}
|
||||
```
|
||||
Reference in New Issue
Block a user