# 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.
