# 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 ` - Refresh token para renovación automática ## Headers Estándar ``` Authorization: Bearer Content-Type: application/json X-Tenant-ID: # Requerido para endpoints multi-tenant X-Correlation-ID: # 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