Files
WhatsAppCentralizado/docs/api/README.md
Claude AI a92a7efccc 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>
2026-01-29 09:29:57 +00:00

12 KiB

API Reference

Información General

  • Base URL: https://tu-dominio.com/api
  • Autenticación: Bearer Token (JWT)
  • Content-Type: application/json

Autenticación

Login

POST /auth/login

Request:

{
  "email": "usuario@empresa.com",
  "password": "tu_password"
}

Response:

{
  "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
  "token_type": "bearer",
  "user": {
    "id": "uuid",
    "email": "usuario@empresa.com",
    "name": "Usuario",
    "role": "admin"
  }
}

Refresh Token

POST /auth/refresh

Logout

POST /auth/logout

Usuario Actual

GET /auth/me

Usuarios

Listar Usuarios

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

POST /api/users

Request:

{
  "email": "nuevo@empresa.com",
  "password": "password123",
  "name": "Nuevo Usuario",
  "role": "agent"
}

Obtener Usuario

GET /api/users/{user_id}

Actualizar Usuario

PUT /api/users/{user_id}

Eliminar Usuario

DELETE /api/users/{user_id}

Cambiar Estado

PUT /api/users/{user_id}/status

Request:

{
  "status": "away"
}

Cuentas WhatsApp

Listar Cuentas

GET /api/whatsapp/accounts

Crear Cuenta (Iniciar conexión)

POST /api/whatsapp/accounts

Request:

{
  "name": "Ventas Principal"
}

Response:

{
  "id": "uuid",
  "name": "Ventas Principal",
  "status": "disconnected",
  "qr_code": null
}

Obtener QR Code

GET /api/whatsapp/accounts/{account_id}/qr

Response:

{
  "qr_code": "data:image/png;base64,..."
}

Estado de Cuenta

GET /api/whatsapp/accounts/{account_id}/status

Desconectar Cuenta

POST /api/whatsapp/accounts/{account_id}/disconnect

Reconectar Cuenta

POST /api/whatsapp/accounts/{account_id}/reconnect

Contactos

Listar Contactos

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

POST /api/contacts

Request:

{
  "phone_number": "+525551234567",
  "name": "Juan Pérez",
  "email": "juan@email.com",
  "company": "Empresa ABC",
  "tags": ["lead", "interesado"],
  "metadata": {
    "producto_interes": "Laptop Pro"
  }
}

Obtener Contacto

GET /api/contacts/{contact_id}

Actualizar Contacto

PUT /api/contacts/{contact_id}

Agregar Etiquetas

POST /api/contacts/{contact_id}/tags

Request:

{
  "tags": ["vip", "cliente"]
}

Sincronizar con Odoo

POST /api/contacts/{contact_id}/sync-odoo

Conversaciones

Listar Conversaciones

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

GET /api/conversations/{conversation_id}

Response:

{
  "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

POST /api/conversations/{conversation_id}/assign

Request:

{
  "user_id": "uuid"
}

Transferir a Cola

POST /api/conversations/{conversation_id}/transfer

Request:

{
  "queue_id": "uuid"
}

Resolver Conversación

POST /api/conversations/{conversation_id}/resolve

Request:

{
  "resolution_note": "Problema resuelto"
}

Reabrir Conversación

POST /api/conversations/{conversation_id}/reopen

Mensajes

Listar Mensajes de Conversación

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

POST /api/conversations/{conversation_id}/messages

Request (texto):

{
  "type": "text",
  "content": "Hola, ¿en qué te puedo ayudar?"
}

Request (imagen):

{
  "type": "image",
  "media_url": "https://example.com/image.jpg",
  "content": "Caption opcional"
}

Request (botones):

{
  "type": "buttons",
  "content": "¿Qué necesitas?",
  "metadata": {
    "buttons": [
      {"id": "ventas", "text": "Ventas"},
      {"id": "soporte", "text": "Soporte"},
      {"id": "otro", "text": "Otro"}
    ]
  }
}

Request (lista):

{
  "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

POST /api/conversations/{conversation_id}/notes

Request:

{
  "content": "Cliente interesado, dar seguimiento"
}

Flujos

Listar Flujos

GET /api/flows

Crear Flujo

POST /api/flows

Request:

{
  "name": "Bienvenida",
  "description": "Flujo de bienvenida para nuevos contactos",
  "trigger_type": "welcome",
  "trigger_value": null,
  "nodes": {
    "nodes": [...],
    "edges": [...],
    "viewport": {...}
  },
  "is_active": true
}

Obtener Flujo

GET /api/flows/{flow_id}

Actualizar Flujo

PUT /api/flows/{flow_id}

Duplicar Flujo

POST /api/flows/{flow_id}/duplicate

Activar/Desactivar Flujo

PUT /api/flows/{flow_id}/toggle

Probar Flujo

POST /api/flows/{flow_id}/test

Request:

{
  "phone_number": "+525551234567",
  "initial_message": "Hola"
}

Colas

Listar Colas

GET /api/queues

Crear Cola

POST /api/queues

Request:

{
  "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

GET /api/queues/{queue_id}

Actualizar Cola

PUT /api/queues/{queue_id}

Agregar Agente a Cola

POST /api/queues/{queue_id}/agents

Request:

{
  "user_id": "uuid",
  "is_supervisor": false,
  "skills": ["ventas", "ingles"]
}

Remover Agente de Cola

DELETE /api/queues/{queue_id}/agents/{user_id}

Estadísticas de Cola

GET /api/queues/{queue_id}/stats

Response:

{
  "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

GET /api/quick-replies

Crear Respuesta Rápida

POST /api/quick-replies

Request:

{
  "shortcut": "/saludo",
  "content": "¡Hola {{contact.name}}! Soy {{agent.name}}, ¿en qué te puedo ayudar?",
  "queue_id": null
}

Actualizar Respuesta Rápida

PUT /api/quick-replies/{id}

Eliminar Respuesta Rápida

DELETE /api/quick-replies/{id}

Odoo

Probar Conexión

POST /api/odoo/test-connection

Sincronizar Contactos

POST /api/odoo/sync-contacts

Buscar Partner

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

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

GET /api/odoo/products/{product_id}/stock

Crear Lead

POST /api/odoo/leads

Request:

{
  "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

const socket = io('wss://tu-dominio.com', {
  auth: {
    token: 'Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...'
  }
});

Eventos del Servidor

Nuevo mensaje:

socket.on('new_message', (data) => {
  // data: { conversation_id, message }
});

Estado de mensaje:

socket.on('message_status', (data) => {
  // data: { message_id, status: 'delivered' | 'read' }
});

Conversación asignada:

socket.on('conversation_assigned', (data) => {
  // data: { conversation_id, assigned_to }
});

QR Code:

socket.on('qr_code', (data) => {
  // data: { account_id, qr_code }
});

Estado de conexión WhatsApp:

socket.on('connection_status', (data) => {
  // data: { account_id, status: 'connected' | 'disconnected' }
});

Eventos del Cliente

Unirse a conversación:

socket.emit('join_conversation', { conversation_id: 'uuid' });

Escribiendo:

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:

{
  "detail": {
    "code": "VALIDATION_ERROR",
    "message": "El campo email es requerido",
    "field": "email"
  }
}