547 lines
11 KiB
Markdown
547 lines
11 KiB
Markdown
# API Contract - ServiceManagerWeb
|
|
# Mesa de Ayuda B2B - Especificación de Endpoints
|
|
|
|
## Base URL
|
|
- Desarrollo: `http://localhost:8000`
|
|
- Producción: `https://api.servicemanager.aduanasoft.com`
|
|
|
|
## Versionado
|
|
- Todos los endpoints tienen prefijo `/v1/`
|
|
- Versionado en URL path (no headers)
|
|
|
|
## Autenticación
|
|
- JWT Bearer Token en header `Authorization: Bearer <token>`
|
|
- Refresh token para renovación automática
|
|
|
|
## Headers Estándar
|
|
```
|
|
Authorization: Bearer <jwt_token>
|
|
Content-Type: application/json
|
|
X-Tenant-ID: <tenant_uuid> # Requerido para endpoints multi-tenant
|
|
X-Correlation-ID: <uuid> # Opcional para tracking
|
|
Accept-Language: es-ES # Para internacionalización
|
|
```
|
|
|
|
## Responses Estándar
|
|
|
|
### Éxito (2xx)
|
|
```json
|
|
{
|
|
"success": true,
|
|
"data": { ... },
|
|
"message": "Operación exitosa",
|
|
"metadata": {
|
|
"page": 1,
|
|
"per_page": 20,
|
|
"total": 150,
|
|
"total_pages": 8
|
|
}
|
|
}
|
|
```
|
|
|
|
### Error (4xx/5xx)
|
|
```json
|
|
{
|
|
"success": false,
|
|
"error": {
|
|
"code": "VALIDATION_ERROR",
|
|
"message": "Datos inválidos",
|
|
"details": [
|
|
{
|
|
"field": "email",
|
|
"message": "Email inválido"
|
|
}
|
|
]
|
|
},
|
|
"correlation_id": "uuid"
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## DOMINIO: AUTH
|
|
|
|
### POST /v1/auth/login
|
|
**Descripción**: Autenticación de usuario
|
|
**Público**: Sí
|
|
|
|
**Request Body**:
|
|
```json
|
|
{
|
|
"email": "user@example.com",
|
|
"password": "password123",
|
|
"tenant_slug": "aduanasoft-demo",
|
|
"totp_code": "123456" // opcional, solo si 2FA activado
|
|
}
|
|
```
|
|
|
|
**Response 200**:
|
|
```json
|
|
{
|
|
"success": true,
|
|
"data": {
|
|
"access_token": "jwt_token",
|
|
"refresh_token": "refresh_token",
|
|
"expires_in": 3600,
|
|
"user": {
|
|
"id": "uuid",
|
|
"email": "user@example.com",
|
|
"first_name": "Juan",
|
|
"last_name": "Pérez",
|
|
"role": "AGENT",
|
|
"tenant": {
|
|
"id": "uuid",
|
|
"name": "Aduanasoft Demo",
|
|
"slug": "aduanasoft-demo"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### POST /v1/auth/refresh
|
|
**Descripción**: Renovar access token
|
|
**Público**: Sí
|
|
|
|
**Request Body**:
|
|
```json
|
|
{
|
|
"refresh_token": "refresh_token"
|
|
}
|
|
```
|
|
|
|
### POST /v1/auth/logout
|
|
**Descripción**: Cerrar sesión (revoca refresh token)
|
|
**Autenticado**: Sí
|
|
|
|
### GET /v1/auth/me
|
|
**Descripción**: Información del usuario actual
|
|
**Autenticado**: Sí
|
|
|
|
### PUT /v1/auth/me
|
|
**Descripción**: Actualizar perfil propio
|
|
**Autenticado**: Sí
|
|
|
|
**Request Body**:
|
|
```json
|
|
{
|
|
"first_name": "Juan",
|
|
"last_name": "Pérez",
|
|
"language": "es",
|
|
"timezone": "America/Mexico_City",
|
|
"notifications_email": true
|
|
}
|
|
```
|
|
|
|
### POST /v1/auth/change-password
|
|
**Descripción**: Cambiar contraseña
|
|
**Autenticado**: Sí
|
|
|
|
### POST /v1/auth/2fa/setup
|
|
**Descripción**: Configurar 2FA (solo roles internos)
|
|
**Autenticado**: Sí, Roles: ADMIN, SUPPORT_MANAGER, AGENT, AUDITOR
|
|
|
|
### POST /v1/auth/2fa/verify
|
|
**Descripción**: Verificar código 2FA durante setup
|
|
**Autenticado**: Sí
|
|
|
|
---
|
|
|
|
## DOMINIO: TENANTS
|
|
|
|
### GET /v1/tenants/current
|
|
**Descripción**: Información del tenant actual
|
|
**Autenticado**: Sí
|
|
|
|
### PUT /v1/tenants/current
|
|
**Descripción**: Actualizar tenant (solo CLIENT_ADMIN/ADMIN)
|
|
**Autenticado**: Sí, Roles: CLIENT_ADMIN, ADMIN
|
|
|
|
### GET /v1/tenants (solo ADMIN)
|
|
**Descripción**: Listar todos los tenants
|
|
**Autenticado**: Sí, Roles: ADMIN
|
|
|
|
### POST /v1/tenants (solo ADMIN)
|
|
**Descripción**: Crear nuevo tenant
|
|
**Autenticado**: Sí, Roles: ADMIN
|
|
|
|
---
|
|
|
|
## DOMINIO: USERS
|
|
|
|
### GET /v1/users
|
|
**Descripción**: Listar usuarios del tenant
|
|
**Autenticado**: Sí
|
|
**Roles**: Todos (filtros por rol)
|
|
|
|
**Query Params**:
|
|
```
|
|
?page=1&per_page=20&role=AGENT&is_active=true&search=juan
|
|
```
|
|
|
|
**Response 200**:
|
|
```json
|
|
{
|
|
"success": true,
|
|
"data": [
|
|
{
|
|
"id": "uuid",
|
|
"email": "agent@example.com",
|
|
"first_name": "Juan",
|
|
"last_name": "Agente",
|
|
"role": "AGENT",
|
|
"is_active": true,
|
|
"email_verified": true,
|
|
"last_login": "2024-01-15T10:30:00Z",
|
|
"created_at": "2024-01-01T00:00:00Z"
|
|
}
|
|
],
|
|
"metadata": {
|
|
"page": 1,
|
|
"per_page": 20,
|
|
"total": 150,
|
|
"total_pages": 8
|
|
}
|
|
}
|
|
```
|
|
|
|
### POST /v1/users
|
|
**Descripción**: Crear usuario
|
|
**Autenticado**: Sí, Roles: ADMIN, SUPPORT_MANAGER, CLIENT_ADMIN
|
|
|
|
**Request Body**:
|
|
```json
|
|
{
|
|
"email": "nuevo@example.com",
|
|
"first_name": "Nuevo",
|
|
"last_name": "Usuario",
|
|
"role": "AGENT",
|
|
"password": "temporal123", // opcional, se genera automáticamente
|
|
"send_welcome_email": true
|
|
}
|
|
```
|
|
|
|
### GET /v1/users/{user_id}
|
|
**Descripción**: Obtener usuario específico
|
|
**Autenticado**: Sí
|
|
|
|
### PUT /v1/users/{user_id}
|
|
**Descripción**: Actualizar usuario
|
|
**Autenticado**: Sí, Roles: ADMIN, SUPPORT_MANAGER, CLIENT_ADMIN
|
|
|
|
### DELETE /v1/users/{user_id}
|
|
**Descripción**: Desactivar usuario (soft delete)
|
|
**Autenticado**: Sí, Roles: ADMIN, SUPPORT_MANAGER, CLIENT_ADMIN
|
|
|
|
---
|
|
|
|
## DOMINIO: TICKETS
|
|
|
|
### GET /v1/tickets
|
|
**Descripción**: Listar tickets con filtros
|
|
**Autenticado**: Sí
|
|
|
|
**Query Params**:
|
|
```
|
|
?page=1&per_page=20
|
|
&status=NEW,IN_PROGRESS
|
|
&priority=HIGH,URGENT
|
|
&assigned_to=uuid
|
|
&created_by=uuid
|
|
&category_id=uuid
|
|
&search=problema+conexion
|
|
&sort=created_at_desc
|
|
&date_from=2024-01-01
|
|
&date_to=2024-01-31
|
|
```
|
|
|
|
**Response 200**:
|
|
```json
|
|
{
|
|
"success": true,
|
|
"data": [
|
|
{
|
|
"id": "uuid",
|
|
"ticket_number": "TKT-2024-000001",
|
|
"subject": "Problema de conexión",
|
|
"status": "IN_PROGRESS",
|
|
"priority": "HIGH",
|
|
"category": {
|
|
"id": "uuid",
|
|
"name": "Soporte Técnico"
|
|
},
|
|
"created_by": {
|
|
"id": "uuid",
|
|
"first_name": "Juan",
|
|
"last_name": "Cliente"
|
|
},
|
|
"assigned_to": {
|
|
"id": "uuid",
|
|
"first_name": "Ana",
|
|
"last_name": "Soporte"
|
|
},
|
|
"sla_response_due": "2024-01-15T12:00:00Z",
|
|
"sla_resolution_due": "2024-01-16T10:00:00Z",
|
|
"created_at": "2024-01-15T10:00:00Z",
|
|
"updated_at": "2024-01-15T11:30:00Z"
|
|
}
|
|
],
|
|
"metadata": {
|
|
"page": 1,
|
|
"per_page": 20,
|
|
"total": 150,
|
|
"total_pages": 8
|
|
}
|
|
}
|
|
```
|
|
|
|
### POST /v1/tickets
|
|
**Descripción**: Crear nuevo ticket
|
|
**Autenticado**: Sí
|
|
|
|
**Request Body**:
|
|
```json
|
|
{
|
|
"subject": "Problema de conexión con el sistema",
|
|
"description": "Descripción detallada del problema...",
|
|
"priority": "HIGH",
|
|
"category_id": "uuid",
|
|
"affected_system_id": "uuid",
|
|
"attachments": [
|
|
{
|
|
"filename": "screenshot.png",
|
|
"content_type": "image/png",
|
|
"content_base64": "base64_data"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
**Response 201**:
|
|
```json
|
|
{
|
|
"success": true,
|
|
"data": {
|
|
"id": "uuid",
|
|
"ticket_number": "TKT-2024-000001",
|
|
"subject": "Problema de conexión con el sistema",
|
|
"status": "NEW",
|
|
"sla_response_due": "2024-01-15T12:00:00Z",
|
|
"created_at": "2024-01-15T10:00:00Z"
|
|
}
|
|
}
|
|
```
|
|
|
|
### GET /v1/tickets/{ticket_id}
|
|
**Descripción**: Obtener ticket completo con comentarios
|
|
**Autenticado**: Sí
|
|
|
|
**Response 200**:
|
|
```json
|
|
{
|
|
"success": true,
|
|
"data": {
|
|
"id": "uuid",
|
|
"ticket_number": "TKT-2024-000001",
|
|
"subject": "Problema de conexión",
|
|
"description": "Descripción completa...",
|
|
"status": "IN_PROGRESS",
|
|
"priority": "HIGH",
|
|
"category": {...},
|
|
"affected_system": {...},
|
|
"created_by": {...},
|
|
"assigned_to": {...},
|
|
"attachments": [...],
|
|
"comments": [
|
|
{
|
|
"id": "uuid",
|
|
"content": "Comentario del ticket...",
|
|
"author": {...},
|
|
"is_internal": false,
|
|
"attachments": [...],
|
|
"created_at": "2024-01-15T11:00:00Z"
|
|
}
|
|
],
|
|
"status_history": [...],
|
|
"sla_metrics": {
|
|
"response_due": "2024-01-15T12:00:00Z",
|
|
"resolution_due": "2024-01-16T10:00:00Z",
|
|
"first_response_at": "2024-01-15T11:15:00Z",
|
|
"response_sla_met": true,
|
|
"resolution_sla_met": null
|
|
},
|
|
"created_at": "2024-01-15T10:00:00Z",
|
|
"updated_at": "2024-01-15T11:30:00Z"
|
|
}
|
|
}
|
|
```
|
|
|
|
### PUT /v1/tickets/{ticket_id}
|
|
**Descripción**: Actualizar ticket (estado, asignación, etc.)
|
|
**Autenticado**: Sí
|
|
|
|
**Request Body**:
|
|
```json
|
|
{
|
|
"status": "IN_PROGRESS",
|
|
"assigned_to": "uuid",
|
|
"priority": "URGENT",
|
|
"comment": "Escalando por alta prioridad"
|
|
}
|
|
```
|
|
|
|
### POST /v1/tickets/{ticket_id}/comments
|
|
**Descripción**: Agregar comentario al ticket
|
|
**Autenticado**: Sí
|
|
|
|
**Request Body**:
|
|
```json
|
|
{
|
|
"content": "Comentario con solución propuesta...",
|
|
"is_internal": false,
|
|
"attachments": [
|
|
{
|
|
"filename": "solution.pdf",
|
|
"content_type": "application/pdf",
|
|
"content_base64": "base64_data"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
### PUT /v1/tickets/{ticket_id}/rating
|
|
**Descripción**: Calificar ticket resuelto (solo cliente)
|
|
**Autenticado**: Sí, Roles: CLIENT_ADMIN, CLIENT_USER
|
|
|
|
**Request Body**:
|
|
```json
|
|
{
|
|
"rating": 5,
|
|
"comment": "Excelente atención y resolución rápida"
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## DOMINIO: CATEGORIES & SYSTEMS
|
|
|
|
### GET /v1/categories
|
|
**Descripción**: Listar categorías del tenant
|
|
**Autenticado**: Sí
|
|
|
|
### POST /v1/categories (solo staff interno)
|
|
**Descripción**: Crear categoría
|
|
**Autenticado**: Sí, Roles: ADMIN, SUPPORT_MANAGER
|
|
|
|
### GET /v1/affected-systems
|
|
**Descripción**: Listar sistemas afectados
|
|
**Autenticado**: Sí
|
|
|
|
---
|
|
|
|
## DOMINIO: NOTIFICATIONS
|
|
|
|
### GET /v1/notifications/templates (solo staff interno)
|
|
**Descripción**: Listar templates de email
|
|
**Autenticado**: Sí, Roles: ADMIN, SUPPORT_MANAGER
|
|
|
|
### POST /v1/notifications/test-email (solo ADMIN)
|
|
**Descripción**: Enviar email de prueba
|
|
**Autenticado**: Sí, Roles: ADMIN
|
|
|
|
---
|
|
|
|
## DOMINIO: REPORTS & ANALYTICS
|
|
|
|
### GET /v1/reports/dashboard
|
|
**Descripción**: Métricas del dashboard
|
|
**Autenticado**: Sí
|
|
|
|
**Response 200**:
|
|
```json
|
|
{
|
|
"success": true,
|
|
"data": {
|
|
"tickets": {
|
|
"total": 150,
|
|
"new": 12,
|
|
"in_progress": 45,
|
|
"waiting_customer": 8,
|
|
"resolved_today": 15
|
|
},
|
|
"sla": {
|
|
"response_rate": 95.5,
|
|
"resolution_rate": 87.2
|
|
},
|
|
"agents": {
|
|
"active": 8,
|
|
"avg_load": 5.6
|
|
},
|
|
"csat": {
|
|
"average": 4.2,
|
|
"total_responses": 89
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### GET /v1/reports/tickets
|
|
**Descripción**: Reporte de tickets con filtros
|
|
**Autenticado**: Sí
|
|
|
|
---
|
|
|
|
## DOMINIO: AUDIT
|
|
|
|
### GET /v1/audit/logs (solo AUDITOR/ADMIN)
|
|
**Descripción**: Consultar logs de auditoría
|
|
**Autenticado**: Sí, Roles: AUDITOR, ADMIN
|
|
|
|
**Query Params**:
|
|
```
|
|
?page=1&per_page=50
|
|
&action=ticket.create,ticket.assign
|
|
&user_id=uuid
|
|
&resource_type=ticket
|
|
&date_from=2024-01-01
|
|
&date_to=2024-01-31
|
|
```
|
|
|
|
---
|
|
|
|
## CÓDIGOS DE ERROR ESTÁNDAR
|
|
|
|
- `400` - Bad Request (datos inválidos)
|
|
- `401` - Unauthorized (no autenticado)
|
|
- `403` - Forbidden (sin permisos)
|
|
- `404` - Not Found (recurso no encontrado)
|
|
- `409` - Conflict (recurso duplicado)
|
|
- `422` - Unprocessable Entity (validación fallida)
|
|
- `429` - Too Many Requests (rate limit)
|
|
- `500` - Internal Server Error
|
|
|
|
## RATE LIMITING
|
|
|
|
- Auth endpoints: 10 req/min por IP
|
|
- API endpoints: 100 req/min por usuario
|
|
- File uploads: 5 req/min por usuario
|
|
|
|
## PAGINACIÓN
|
|
|
|
- Default: `per_page=20`, `max=100`
|
|
- Links de navegación en metadata
|
|
- Total count incluido cuando sea eficiente
|
|
|
|
## ORDENAMIENTO
|
|
|
|
Formato: `?sort=field_direction`
|
|
- `created_at_desc` (default)
|
|
- `updated_at_desc`
|
|
- `priority_desc`
|
|
- `status_asc`
|
|
|
|
## BÚSQUEDA
|
|
|
|
- Full-text search en `subject` y `description`
|
|
- Búsqueda por número de ticket exacto
|
|
- Filtros combinables con AND lógico |