Initial commit: SKEEN Derma Experts - Sistema Integral de Gestión Clínica
- Frontend React (SKEEN Brand) con Vite, TypeScript, Tailwind - Frontend Homenest (versión alternativa) - Módulos Odoo 17 custom (citas, pacientes, monedero, pagos, ventas, inventario, whatsapp) - WACRM fork (Next.js 16 + Supabase) - Hermes + Bridge + Skills (Qwen3.6 via Nan Builders) - Scripts de migración y operación - Documentación extensiva en docs/
This commit is contained in:
738
docs/api.md
Normal file
738
docs/api.md
Normal file
@@ -0,0 +1,738 @@
|
||||
# API Reference — SKEEN Derma Experts
|
||||
|
||||
**Versión:** 2.0
|
||||
**Fecha:** 16 de julio de 2026
|
||||
|
||||
---
|
||||
|
||||
## 1. Introducción
|
||||
|
||||
Esta documentación describe todos los endpoints REST expuestos por el sistema SKEEN. Los endpoints están organizados por componente:
|
||||
|
||||
- **Odoo Frontend API** (`/skeen/frontend/v1/*`): Para el Frontend React.
|
||||
- **Odoo Hermes API** (`/skeen/api/v1/*`): Para Hermes/skills (JSON-RPC/XML-RPC).
|
||||
- **WACRM API** (`/api/v1/*`): Para WACRM público.
|
||||
- **Bridge API** (`:8090/*`): Para webhooks WACRM → Hermes.
|
||||
|
||||
---
|
||||
|
||||
## 2. Autenticación
|
||||
|
||||
### 2.1 Frontend API (JWT)
|
||||
|
||||
```bash
|
||||
# Login
|
||||
curl -X POST http://localhost:8069/skeen/frontend/v1/auth/login \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"login":"admin","password":"SkeenAdmin2026!"}'
|
||||
|
||||
# Respuesta
|
||||
{
|
||||
"status": "success",
|
||||
"token": "eyJ1aWQiOjEsImxvZ2luIjoiYWRtaW4iLCJyb2xlIjoiYWRtaW4iLCJleHAiOjE3ODQyMzI3NDV9...",
|
||||
"user": {
|
||||
"id": 1,
|
||||
"login": "admin",
|
||||
"name": "Administrador SKEEN",
|
||||
"role": "admin"
|
||||
}
|
||||
}
|
||||
|
||||
# Uso del token
|
||||
curl -H "Authorization: Bearer <token>" http://localhost:8069/skeen/frontend/v1/appointments
|
||||
```
|
||||
|
||||
### 2.2 Hermes API (API Key)
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:8069/skeen/api/v1/available_slots \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer skeen_api_key_2026" \
|
||||
-d '{"service_id":1,"date_from":"2026-07-17","date_to":"2026-07-20"}'
|
||||
```
|
||||
|
||||
### 2.3 WACRM API (Bearer Token)
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:3000/api/v1/messages \
|
||||
-H "Authorization: Bearer wacrm_live_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"to":"+526641234567","type":"text","text":"Hola"}'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Odoo Frontend API
|
||||
|
||||
### 3.1 Health
|
||||
|
||||
```http
|
||||
GET /skeen/frontend/v1/health
|
||||
```
|
||||
|
||||
**Respuesta:**
|
||||
```json
|
||||
{
|
||||
"status": "ok",
|
||||
"service": "skeen-frontend-api",
|
||||
"version": "1.1.0"
|
||||
}
|
||||
```
|
||||
|
||||
### 3.2 Auth
|
||||
|
||||
#### Login
|
||||
|
||||
```http
|
||||
POST /skeen/frontend/v1/auth/login
|
||||
```
|
||||
|
||||
**Body:**
|
||||
```json
|
||||
{
|
||||
"login": "admin",
|
||||
"password": "SkeenAdmin2026!"
|
||||
}
|
||||
```
|
||||
|
||||
**Respuesta:**
|
||||
```json
|
||||
{
|
||||
"status": "success",
|
||||
"token": "eyJ...",
|
||||
"user": {
|
||||
"id": 1,
|
||||
"login": "admin",
|
||||
"name": "Administrador SKEEN",
|
||||
"role": "admin",
|
||||
"must_change_password": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Me
|
||||
|
||||
```http
|
||||
GET /skeen/frontend/v1/auth/me
|
||||
Authorization: Bearer <token>
|
||||
```
|
||||
|
||||
#### Logout
|
||||
|
||||
```http
|
||||
POST /skeen/frontend/v1/auth/logout
|
||||
Authorization: Bearer <token>
|
||||
```
|
||||
|
||||
#### Listar Usuarios (admin)
|
||||
|
||||
```http
|
||||
GET /skeen/frontend/v1/auth/users
|
||||
Authorization: Bearer <token>
|
||||
```
|
||||
|
||||
#### Crear Usuario (admin)
|
||||
|
||||
```http
|
||||
POST /skeen/frontend/v1/auth/users
|
||||
Authorization: Bearer <token>
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"login": "recepcion1",
|
||||
"name": "Recepción 1",
|
||||
"password": "Password123!",
|
||||
"role": "recepcion"
|
||||
}
|
||||
```
|
||||
|
||||
#### Actualizar Usuario (admin)
|
||||
|
||||
```http
|
||||
PUT /skeen/frontend/v1/auth/users/<user_id>
|
||||
Authorization: Bearer <token>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3.3 Citas
|
||||
|
||||
#### Listar Citas
|
||||
|
||||
```http
|
||||
GET /skeen/frontend/v1/appointments?page=1&page_size=50&date_from=2026-07-01&date_to=2026-07-31&state=confirmed&search=Nombre
|
||||
Authorization: Bearer <token>
|
||||
```
|
||||
|
||||
**Parámetros de query:**
|
||||
- `page`: Número de página (default: 1)
|
||||
- `page_size`: Items por página (default: 50, max: 200)
|
||||
- `date_from`: Fecha inicio (YYYY-MM-DD)
|
||||
- `date_to`: Fecha fin (YYYY-MM-DD)
|
||||
- `state`: Estado (`pending`, `confirmed`, `arrived`, `in_progress`, `done`, `cancelled`, `no_show`)
|
||||
- `patient_id`: ID del paciente
|
||||
- `doctor_id`: ID del médico
|
||||
- `search`: Búsqueda por nombre, paciente o servicio
|
||||
|
||||
**Respuesta:**
|
||||
```json
|
||||
{
|
||||
"status": "success",
|
||||
"appointments": [
|
||||
{
|
||||
"id": 1,
|
||||
"reference": "CITA-001",
|
||||
"patient_id": 45044,
|
||||
"patient": "Negrete Ca Mou Cecile",
|
||||
"phone": "526634347178",
|
||||
"service_id": 1,
|
||||
"service": "Consulta Dermatologica",
|
||||
"service_category": "consulta",
|
||||
"date": "2026-07-17",
|
||||
"time": "10:00",
|
||||
"state": "pending",
|
||||
"payment_state": "not_paid",
|
||||
"price": 800.0,
|
||||
"doctor_id": null,
|
||||
"doctor": null,
|
||||
"branch": "rosarito",
|
||||
"medium": "onsite",
|
||||
"notes": "",
|
||||
"package_finished": false,
|
||||
"package_finished_date": null
|
||||
}
|
||||
],
|
||||
"total": 1,
|
||||
"page": 1,
|
||||
"page_size": 50,
|
||||
"total_pages": 1
|
||||
}
|
||||
```
|
||||
|
||||
#### Crear Cita
|
||||
|
||||
```http
|
||||
POST /skeen/frontend/v1/appointments
|
||||
Authorization: Bearer <token>
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"partner_id": 45044,
|
||||
"servicio_id": 1,
|
||||
"date": "2026-07-17",
|
||||
"time": 10.0,
|
||||
"sessions": 1,
|
||||
"branch": "rosarito",
|
||||
"medium": "onsite",
|
||||
"notes": "",
|
||||
"state": "pending"
|
||||
}
|
||||
```
|
||||
|
||||
**Campos:**
|
||||
- `partner_id` (required): ID del paciente
|
||||
- `servicio_id` (required): ID del servicio
|
||||
- `date` (required): Fecha (YYYY-MM-DD)
|
||||
- `time` (required): Hora en float (10.0 = 10:00, 10.5 = 10:30)
|
||||
- `sessions` (optional): Número de sesiones (default: 1). Si el servicio tiene `package_sessions > 0`, se usa ese valor por defecto.
|
||||
- `branch` (optional): `rosarito` o `tijuana`
|
||||
- `medium` (optional): `onsite` o `videocall`
|
||||
- `notes` (optional): Notas
|
||||
- `state` (optional): Estado inicial
|
||||
|
||||
**Respuesta:**
|
||||
```json
|
||||
{
|
||||
"status": "success",
|
||||
"appointment": { /* primera cita */ },
|
||||
"appointments": [ /* todas las citas creadas */ ],
|
||||
"sessions": 3
|
||||
}
|
||||
```
|
||||
|
||||
**Nota:** Si `sessions > 1`, se crean N citas separadas. La primera usa la fecha/hora proporcionada; las siguientes se programan cada 7 días a las 9:00 AM.
|
||||
|
||||
#### Obtener Cita
|
||||
|
||||
```http
|
||||
GET /skeen/frontend/v1/appointments/<appointment_id>
|
||||
Authorization: Bearer <token>
|
||||
```
|
||||
|
||||
#### Actualizar Cita
|
||||
|
||||
```http
|
||||
PUT /skeen/frontend/v1/appointments/<appointment_id>
|
||||
Authorization: Bearer <token>
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"date": "2026-07-18",
|
||||
"time": 11.0,
|
||||
"state": "confirmed",
|
||||
"notes": "Paciente confirmó por teléfono"
|
||||
}
|
||||
```
|
||||
|
||||
#### Eliminar Cita
|
||||
|
||||
```http
|
||||
DELETE /skeen/frontend/v1/appointments/<appointment_id>
|
||||
Authorization: Bearer <token>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3.4 Servicios
|
||||
|
||||
#### Listar Servicios
|
||||
|
||||
```http
|
||||
GET /skeen/frontend/v1/services
|
||||
Authorization: Bearer <token>
|
||||
```
|
||||
|
||||
**Respuesta:**
|
||||
```json
|
||||
{
|
||||
"status": "success",
|
||||
"services": [
|
||||
{
|
||||
"id": 1,
|
||||
"code": "CONS-DERM",
|
||||
"name": "Consulta Dermatologica",
|
||||
"category": "consulta",
|
||||
"price": 800.0,
|
||||
"package_price": 0.0,
|
||||
"package_sessions": 0,
|
||||
"package_notes": "",
|
||||
"duration_min": 30,
|
||||
"description": "Evaluación completa...",
|
||||
"color": "#1abc9c",
|
||||
"service_group": "Consultas",
|
||||
"is_favorite": true
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
#### Crear Servicio (admin)
|
||||
|
||||
```http
|
||||
POST /skeen/frontend/v1/services
|
||||
Authorization: Bearer <token>
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"name": "Peel Quimico",
|
||||
"code": "PEEL-QUI",
|
||||
"category": "tratamiento",
|
||||
"price": 1500.0,
|
||||
"duration_min": 30,
|
||||
"package_price": 4000.0,
|
||||
"package_sessions": 3,
|
||||
"package_notes": "Ahorro de $500",
|
||||
"description": "Exfoliación química...",
|
||||
"color": "#9b59b6",
|
||||
"service_group": "Faciales",
|
||||
"is_favorite": false
|
||||
}
|
||||
```
|
||||
|
||||
#### Actualizar Servicio (admin)
|
||||
|
||||
```http
|
||||
PUT /skeen/frontend/v1/services/<service_id>
|
||||
Authorization: Bearer <token>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3.5 Pacientes
|
||||
|
||||
#### Listar Pacientes
|
||||
|
||||
```http
|
||||
GET /skeen/frontend/v1/patients?page=1&page_size=50&search=Nombre
|
||||
Authorization: Bearer <token>
|
||||
```
|
||||
|
||||
#### Crear Paciente
|
||||
|
||||
```http
|
||||
POST /skeen/frontend/v1/patients
|
||||
Authorization: Bearer <token>
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"name": "Juan Pérez",
|
||||
"phone": "526641234567",
|
||||
"email": "juan@example.com",
|
||||
"birthdate": "1990-01-15",
|
||||
"gender": "male",
|
||||
"blood_type": "O+",
|
||||
"allergies": "Penicilina",
|
||||
"notes": "Paciente nuevo"
|
||||
}
|
||||
```
|
||||
|
||||
#### Obtener Paciente
|
||||
|
||||
```http
|
||||
GET /skeen/frontend/v1/patients/<patient_id>
|
||||
Authorization: Bearer <token>
|
||||
```
|
||||
|
||||
#### Actualizar Paciente
|
||||
|
||||
```http
|
||||
PUT /skeen/frontend/v1/patients/<patient_id>
|
||||
Authorization: Bearer <token>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3.6 Monedero
|
||||
|
||||
#### Listar Monederos
|
||||
|
||||
```http
|
||||
GET /skeen/frontend/v1/wallets
|
||||
Authorization: Bearer <token>
|
||||
```
|
||||
|
||||
**Respuesta:**
|
||||
```json
|
||||
{
|
||||
"status": "success",
|
||||
"wallets": [
|
||||
{
|
||||
"id": 1,
|
||||
"patient_id": 45044,
|
||||
"patient": "Negrete Ca Mou Cecile",
|
||||
"points": 450,
|
||||
"equivalent_mxn": 450,
|
||||
"transactions": []
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3.7 Ventas
|
||||
|
||||
#### Listar Ventas
|
||||
|
||||
```http
|
||||
GET /skeen/frontend/v1/sales?date_from=2026-07-01&date_to=2026-07-31
|
||||
Authorization: Bearer <token>
|
||||
```
|
||||
|
||||
#### Crear Venta
|
||||
|
||||
```http
|
||||
POST /skeen/frontend/v1/sales
|
||||
Authorization: Bearer <token>
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"partner_id": 45044,
|
||||
"lines": [
|
||||
{
|
||||
"service_id": 1,
|
||||
"qty": 1,
|
||||
"price_unit": 800.0
|
||||
}
|
||||
],
|
||||
"payment_method": "cash",
|
||||
"notes": ""
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3.8 Inventario
|
||||
|
||||
#### Listar Inventario
|
||||
|
||||
```http
|
||||
GET /skeen/frontend/v1/inventory
|
||||
Authorization: Bearer <token>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3.9 WACRM Proxy
|
||||
|
||||
#### Listar Contactos
|
||||
|
||||
```http
|
||||
GET /skeen/frontend/v1/wacrm/contacts?page=1&page_size=50&search=Nombre
|
||||
Authorization: Bearer <token>
|
||||
```
|
||||
|
||||
#### Listar Conversaciones
|
||||
|
||||
```http
|
||||
GET /skeen/frontend/v1/wacrm/conversations?page=1&page_size=50
|
||||
Authorization: Bearer <token>
|
||||
```
|
||||
|
||||
#### Listar Mensajes
|
||||
|
||||
```http
|
||||
GET /skeen/frontend/v1/wacrm/messages?conversation_id=123
|
||||
Authorization: Bearer <token>
|
||||
```
|
||||
|
||||
#### Listar Deals
|
||||
|
||||
```http
|
||||
GET /skeen/frontend/v1/wacrm/deals
|
||||
Authorization: Bearer <token>
|
||||
```
|
||||
|
||||
#### Sincronizar WACRM → Odoo
|
||||
|
||||
```http
|
||||
POST /skeen/frontend/v1/wacrm/sync
|
||||
Authorization: Bearer <token>
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"sync_contacts": true,
|
||||
"sync_conversations": true,
|
||||
"sync_messages": true,
|
||||
"sync_deals": true
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Odoo Hermes API
|
||||
|
||||
Estos endpoints usan `type='json'` y `auth='api_key'`.
|
||||
|
||||
### 4.1 Slots Disponibles
|
||||
|
||||
```http
|
||||
POST /skeen/api/v1/available_slots
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer <api_key>
|
||||
|
||||
{
|
||||
"service_id": 1,
|
||||
"date_from": "2026-07-17",
|
||||
"date_to": "2026-07-20"
|
||||
}
|
||||
```
|
||||
|
||||
**Respuesta:**
|
||||
```json
|
||||
{
|
||||
"status": "success",
|
||||
"slots": [
|
||||
{
|
||||
"date": "2026-07-17",
|
||||
"time": "09:00",
|
||||
"datetime": "2026-07-17 09:00"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 4.2 Crear Cita
|
||||
|
||||
```http
|
||||
POST /skeen/api/v1/create_appointment
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer <api_key>
|
||||
|
||||
{
|
||||
"phone": "526641234567",
|
||||
"name": "Juan Pérez",
|
||||
"service_id": 1,
|
||||
"date": "2026-07-17",
|
||||
"time": "10:00"
|
||||
}
|
||||
```
|
||||
|
||||
### 4.3 Saldo del Paciente
|
||||
|
||||
```http
|
||||
POST /skeen/api/v1/patient_balance
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer <api_key>
|
||||
|
||||
{
|
||||
"phone": "526641234567"
|
||||
}
|
||||
```
|
||||
|
||||
**Respuesta:**
|
||||
```json
|
||||
{
|
||||
"status": "success",
|
||||
"pending_balance": 1500.0,
|
||||
"pending_invoices": [
|
||||
{
|
||||
"amount_residual": 1500.0,
|
||||
"name": "INV/2026/0001"
|
||||
}
|
||||
],
|
||||
"wallet_points": 450,
|
||||
"wallet_mxn": 450
|
||||
}
|
||||
```
|
||||
|
||||
### 4.4 Redimir Puntos
|
||||
|
||||
```http
|
||||
POST /skeen/api/v1/wallet_redeem
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer <api_key>
|
||||
|
||||
{
|
||||
"phone": "526641234567",
|
||||
"points": 200,
|
||||
"appointment_id": 123
|
||||
}
|
||||
```
|
||||
|
||||
### 4.5 Cancelar Cita
|
||||
|
||||
```http
|
||||
POST /skeen/api/v1/cancel_appointment
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer <api_key>
|
||||
|
||||
{
|
||||
"phone": "526641234567",
|
||||
"booking_id": 123
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. WACRM API
|
||||
|
||||
### 5.1 Enviar Mensaje
|
||||
|
||||
```http
|
||||
POST /api/v1/messages
|
||||
Authorization: Bearer <api_key>
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"to": "+526641234567",
|
||||
"type": "text",
|
||||
"text": "Hola, tu cita está confirmada"
|
||||
}
|
||||
```
|
||||
|
||||
### 5.2 Simular Mensaje (Demo)
|
||||
|
||||
```http
|
||||
POST /api/v1/messages/simulate
|
||||
Authorization: Bearer <api_key>
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"to": "+526641234567",
|
||||
"type": "text",
|
||||
"text": "Hola, tu cita está confirmada"
|
||||
}
|
||||
```
|
||||
|
||||
### 5.3 Contactos
|
||||
|
||||
```http
|
||||
GET /api/v1/contacts
|
||||
Authorization: Bearer <api_key>
|
||||
```
|
||||
|
||||
### 5.4 Webhooks
|
||||
|
||||
```http
|
||||
POST /api/v1/webhooks
|
||||
Authorization: Bearer <api_key>
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"url": "https://openclaw.skeen.mx/webhook/wacrm",
|
||||
"events": ["message.received", "message.status_updated"]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. Bridge API
|
||||
|
||||
### 6.1 Health
|
||||
|
||||
```http
|
||||
GET /health
|
||||
```
|
||||
|
||||
### 6.2 Webhook WACRM
|
||||
|
||||
```http
|
||||
POST /webhook/wacrm
|
||||
Content-Type: application/json
|
||||
X-WACRM-Signature: t=...,v1=...
|
||||
|
||||
{
|
||||
"from": "+526641234567",
|
||||
"text": "Hola, quiero agendar una cita",
|
||||
"conversation_id": "123",
|
||||
"contact_id": "456"
|
||||
}
|
||||
```
|
||||
|
||||
**Respuesta:**
|
||||
```json
|
||||
{
|
||||
"received": true,
|
||||
"response": "Hola! Soy Sofia de SKEEN. Claro, ¿qué servicio te interesa?"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. Códigos de Error
|
||||
|
||||
| Código | Significado |
|
||||
|--------|-------------|
|
||||
| 200 | OK |
|
||||
| 201 | Creado |
|
||||
| 400 | Bad Request — parámetros inválidos |
|
||||
| 401 | Unauthorized — token inválido o faltante |
|
||||
| 403 | Forbidden — permisos insuficientes |
|
||||
| 404 | Not Found — recurso no encontrado |
|
||||
| 409 | Conflict — conflicto (ej. usuario ya existe) |
|
||||
| 500 | Internal Server Error |
|
||||
|
||||
**Formato de error:**
|
||||
```json
|
||||
{
|
||||
"status": "error",
|
||||
"message": "Descripción del error"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. Rate Limiting
|
||||
|
||||
Actualmente no hay rate limiting implementado. Se recomienda configurar:
|
||||
|
||||
- **nginx:** `limit_req_zone`
|
||||
- **WACRM:** Configurar en middleware
|
||||
- **Odoo:** Configurar en `ir.http`
|
||||
|
||||
---
|
||||
|
||||
## 9. Versionado
|
||||
|
||||
La API está en versión `1.1.0`. Los cambios se documentan en el changelog de cada módulo.
|
||||
Reference in New Issue
Block a user