openapi: 3.0.3 info: title: 'Wave API Documentation Gama prueba' description: 'funciona alg' version: 1.0.0 servers: - url: 'https://www.nexasplay.com' tags: - name: Autenticación description: '' - name: 'Billetera de Usuario' description: '' - name: Compañías description: '' - name: Endpoints description: '' - name: Eventos description: '' - name: Filtros description: '' - name: Juegos description: '' - name: 'Reseñas (Reviews)' description: '' - name: Rooms description: '' paths: /api/login: post: summary: 'Iniciar sesión' operationId: iniciarSesin description: "Este endpoint permite autenticar a un usuario mediante correo y contraseña.\nSi las credenciales son correctas, devuelve un token que se utilizará\npara autenticar las siguientes peticiones." parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: access_token: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9... token_type: bearer expires_in: 60 properties: access_token: type: string example: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9... token_type: type: string example: bearer expires_in: type: integer example: 60 401: description: '' content: application/json: schema: type: object example: error: Unauthorized properties: error: type: string example: Unauthorized tags: - Autenticación requestBody: required: true content: application/json: schema: type: object properties: email: type: string description: 'Correo electrónico del usuario. Ejemplo: cliente1@nexaxplay.com' example: qkunze@example.com nullable: false password: type: string description: 'Contraseña del usuario. Ejemplo: 123456789' example: 'O[2UZ5ij-e/dl4m{o,' nullable: false required: - email - password security: [] /api/register: post: summary: 'Registrar un nuevo usuario.' operationId: registrarUnNuevoUsuario description: "Permite crear un nuevo usuario en el sistema proporcionando los datos personales requeridos.\nRetorna un token JWT para autenticación posterior." parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: access_token: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9... token_type: bearer expires_in: 60 properties: access_token: type: string example: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9... token_type: type: string example: bearer expires_in: type: integer example: 60 422: description: '' content: application/json: schema: type: object example: email: - 'The email has already been taken.' properties: email: type: array example: - 'The email has already been taken.' items: type: string tags: - Autenticación requestBody: required: true content: application/json: schema: type: object properties: first_name: type: string description: 'Nombre del usuario. Ejemplo: Sean' example: consequatur nullable: false last_name: type: string description: 'Apellido del usuario. Ejemplo: paul' example: consequatur nullable: false email: type: string description: 'Correo electrónico válido y único. Ejemplo: seanpuol@gmail.com' example: qkunze@example.com nullable: false password: type: string description: 'Contraseña con mínimo 8 caracteres. Ejemplo: 123456789' example: 'O[2UZ5ij-e/dl4m{o,' nullable: false phone: type: string description: 'Número de teléfono único. Ejemplo: 30243614512' example: consequatur nullable: false password_confirmation: type: string description: 'Confirmación de la contraseña. Ejemplo: 123456789' example: consequatur nullable: false birthdate: type: date description: 'Fecha de nacimiento en formato Y-m-d. Ejemplo: 1989-04-15' example: consequatur nullable: false gender: type: string description: 'Género del usuario (M o F). Ejemplo: M' example: consequatur nullable: false current_city: type: string description: 'Ciudad actual del usuario. Ejemplo: Pasto' example: consequatur nullable: false required: - first_name - last_name - email - password - phone - password_confirmation - birthdate - gender - current_city security: [] /api/logout: post: summary: 'Cerrar sesión' operationId: cerrarSesin description: "Este endpoint cierra la sesión del usuario autenticado invalidando su token JWT.\nDespués de cerrar sesión, el token ya no será válido para futuras peticiones." parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: message: 'Successfully logged out' properties: message: type: string example: 'Successfully logged out' 401: description: '' content: application/json: schema: type: object example: message: 'Token inválido o expirado' properties: message: type: string example: 'Token inválido o expirado' tags: - Autenticación security: [] /api/refresh: post: summary: 'Refrescar token JWT' operationId: refrescarTokenJWT description: "Este endpoint permite renovar el token JWT del usuario autenticado cuando está próximo a expirar.\nDevuelve un nuevo token válido que debe reemplazar al anterior en las siguientes peticiones." parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: access_token: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9... token_type: bearer expires_in: 60 properties: access_token: type: string example: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9... token_type: type: string example: bearer expires_in: type: integer example: 60 401: description: '' content: application/json: schema: type: object example: message: 'Token inválido o expirado' properties: message: type: string example: 'Token inválido o expirado' tags: - Autenticación security: [] /api/token: post: summary: 'Obtener token de acceso desde una API Key' operationId: obtenerTokenDeAccesoDesdeUnaAPIKey description: "Este endpoint genera un token JWT válido para el usuario asociado a una API Key.\nSe usa cuando un sistema externo necesita autenticarse sin usar usuario y contraseña." parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: access_token: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9... properties: access_token: type: string example: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9... 400: description: '' content: application/json: schema: type: object example: message: 'Invalid Api Key' properties: message: type: string example: 'Invalid Api Key' 401: description: '' content: application/json: schema: type: object example: message: Unauthorized properties: message: type: string example: Unauthorized tags: - Autenticación requestBody: required: true content: application/json: schema: type: object properties: key: type: string description: 'Clave API válida asociada a un usuario. Ejemplo: 4f9b28b5e912f7a2b1d4c8e7' example: consequatur nullable: false required: - key security: [] /api/user-balances: get: summary: 'Obtener Saldos' operationId: obtenerSaldos description: "Devuelve los saldos actuales de monedas (coins) y el total de tickets (globalTickets)\ndel usuario autenticado." parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: data: coins: 150 globalTickets: 75 properties: data: type: object properties: coins: type: integer example: 150 globalTickets: type: integer example: 75 500: description: '' content: application/json: schema: type: object example: message: 'No se pudieron obtener los saldos. Intenta más tarde.' properties: message: type: string example: 'No se pudieron obtener los saldos. Intenta más tarde.' tags: - 'Billetera de Usuario' security: [] /api/user-transactions: get: summary: 'Historial de Transacciones' operationId: historialDeTransacciones description: "Devuelve un historial paginado de todas las transacciones de monedas y tickets\ndel usuario autenticado, ordenadas por fecha (más recientes primero)." parameters: - in: query name: page description: 'Página del historial que se desea ver.' example: 1 required: false schema: type: integer description: 'Página del historial que se desea ver.' example: 1 nullable: false responses: 200: description: '' content: text/plain: schema: type: string example: "{\n \"current_page\": 1,\n \"data\": [\n {\n \"currency\": \"tickets\",\n \"type\": \"assign\",\n \"amount\": 25,\n \"source\": \"Premio diario\",\n \"date\": \"2025-09-30T10:30:00Z\"\n },\n {\n \"currency\": \"coins\",\n \"type\": \"spend\",\n \"amount\": 10,\n \"source\": \"Jugar a Pac-Man\",\n \"date\": \"2025-09-30T09:15:00Z\"\n }\n ],\n}" tags: - 'Billetera de Usuario' security: [] '/api/companies-edit/{company_id}': put: summary: 'Actualizar una Compañía' operationId: actualizarUnaCompaa description: "Permite a un administrador de compañía actualizar los detalles de su propia compañía.\nEl usuario debe tener el permiso 'edit_companies' y pertenecer a la compañía que intenta actualizar." parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: data: id: 1 name: 'Gama Arcades (Centro)' logoUrl: null description: 'La mejor sala de juegos del centro.' phone: '3109876543' city: Pasto location: '1.2130,-77.2780' labels: - id: 1 name: Restaurante - id: 3 name: Familiar services: - id: 1 name: 'Wi-Fi Gratis' - id: 2 name: Estacionamiento properties: data: type: object properties: id: type: integer example: 1 name: type: string example: 'Gama Arcades (Centro)' logoUrl: type: string example: null description: type: string example: 'La mejor sala de juegos del centro.' phone: type: string example: '3109876543' city: type: string example: Pasto location: type: string example: '1.2130,-77.2780' labels: type: array example: - id: 1 name: Restaurante - id: 3 name: Familiar items: type: object properties: id: type: integer example: 1 name: type: string example: Restaurante services: type: array example: - id: 1 name: 'Wi-Fi Gratis' - id: 2 name: Estacionamiento items: type: object properties: id: type: integer example: 1 name: type: string example: 'Wi-Fi Gratis' 403: description: '' content: application/json: schema: type: object example: message: 'No autorizado para modificar esta compañía.' properties: message: type: string example: 'No autorizado para modificar esta compañía.' 404: description: '' content: application/json: schema: type: object example: message: 'Compañía no encontrada.' properties: message: type: string example: 'Compañía no encontrada.' tags: - Compañías requestBody: required: false content: application/json: schema: type: object properties: name: type: string description: 'El nuevo nombre de la compañía.' example: '"Gama Arcades (Centro)"' nullable: false description: type: string description: 'La nueva descripción.' example: '"La mejor sala de juegos del centro."' nullable: true phone: type: string description: 'El nuevo teléfono.' example: '"3109876543"' nullable: true catalog: type: string description: '' example: consequatur nullable: true schedule: type: string description: 'El nuevo horario.' example: '"L-V: 10am-8pm"' nullable: true address: type: string description: 'La nueva dirección.' example: '"Calle 10 #1-23"' nullable: true city: type: string description: 'Must not be greater than 100 characters.' example: mqeopfuudtdsufvyvddqa nullable: true location: type: string description: 'Las nuevas coordenadas.' example: '"1.2130,-77.2780"' nullable: true game_room: type: string description: '' example: consequatur nullable: true label_ids: type: array description: 'Un array de IDs de las etiquetas que esta compañía debe tener.' example: - 1 - 3 items: type: string security: [] parameters: - in: path name: company_id description: 'The ID of the company.' example: 1 required: true schema: type: integer - in: path name: company description: 'El ID de la compañía a actualizar.' example: '1' required: true schema: type: string /api/match/join: post: summary: '' operationId: postApiMatchJoin description: '' parameters: [] responses: { } tags: - Endpoints security: [] '/api/rooms/{room_id}': get: summary: '' operationId: getApiRoomsRoom_id description: '' parameters: [] responses: 401: description: '' content: application/json: schema: type: object example: message: Unauthenticated. properties: message: type: string example: Unauthenticated. tags: - Endpoints security: [] parameters: - in: path name: room_id description: 'The ID of the room.' example: 4 required: true schema: type: integer /api/user: get: summary: '' operationId: getApiUser description: '' parameters: [] responses: 401: description: '' content: application/json: schema: type: object example: message: Unauthenticated. properties: message: type: string example: Unauthenticated. tags: - Endpoints security: [] '/api/{datatype}': get: summary: '' operationId: getApiDatatype description: '' parameters: [] responses: 401: description: '' content: application/json: schema: type: object example: message: Unauthenticated. properties: message: type: string example: Unauthenticated. tags: - Endpoints security: [] post: summary: '' operationId: postApiDatatype description: '' parameters: [] responses: { } tags: - Endpoints security: [] parameters: - in: path name: datatype description: '' example: consequatur required: true schema: type: string '/api/{datatype}/{id}': get: summary: '' operationId: getApiDatatypeId description: '' parameters: [] responses: 401: description: '' content: application/json: schema: type: object example: message: Unauthenticated. properties: message: type: string example: Unauthenticated. tags: - Endpoints security: [] put: summary: '' operationId: putApiDatatypeId description: '' parameters: [] responses: { } tags: - Endpoints security: [] delete: summary: '' operationId: deleteApiDatatypeId description: '' parameters: [] responses: { } tags: - Endpoints security: [] parameters: - in: path name: datatype description: '' example: consequatur required: true schema: type: string - in: path name: id description: 'The ID of the {datatype}.' example: consequatur required: true schema: type: string '/api/events-leaderboard/{event_id}': get: summary: 'Tabla de Clasificación del Evento (Leaderboard)' operationId: tablaDeClasificacinDelEventoLeaderboard description: "Devuelve la clasificación de los usuarios para un evento específico,\nbasada en la suma de sus puntuaciones en todos los minijuegos de ese evento." parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: data: - rank: 1 user: id: 2 username: usertest firstName: Usuario lastName: Prueba avatarUrl: users/default.png totalScore: 500 - rank: 2 user: id: 1 username: admin firstName: Wave lastName: Admin avatarUrl: users/default.png totalScore: 250 properties: data: type: array example: - rank: 1 user: id: 2 username: usertest firstName: Usuario lastName: Prueba avatarUrl: users/default.png totalScore: 500 - rank: 2 user: id: 1 username: admin firstName: Wave lastName: Admin avatarUrl: users/default.png totalScore: 250 items: type: object properties: rank: type: integer example: 1 user: type: object properties: id: type: integer example: 2 username: type: string example: usertest firstName: type: string example: Usuario lastName: type: string example: Prueba avatarUrl: type: string example: users/default.png totalScore: type: integer example: 500 tags: - Eventos security: [] parameters: - in: path name: event_id description: 'The ID of the event.' example: 1 required: true schema: type: integer - in: path name: event description: 'El ID del evento.' example: '1' required: true schema: type: string '/api/events-leaderboard/{event_id}/my-rank': get: summary: 'Ver Mi Clasificación en un Evento' operationId: verMiClasificacinEnUnEvento description: "Obtiene el puntaje total del usuario para un evento específico\ny su posición (rango) en la tabla de clasificación de ese evento." parameters: [] responses: 200: description: '' content: text/plain: schema: oneOf: - description: '' type: string example: "(Clasificado) {\n \"data\": {\n \"rank\": 2,\n \"totalScore\": 250,\n \"user\": {\n \"id\": 1,\n \"username\": \"admin\",\n \"firstName\": \"Wave\",\n \"lastName\": \"Admin\",\n \"avatarUrl\": \"users/default.png\"\n }\n }\n}" - description: '' type: string example: "(No clasificado) {\n \"data\": {\n \"rank\": null,\n \"totalScore\": 0,\n \"user\": {\n \"id\": 3,\n \"username\": \"carlos\",\n \"firstName\": \"Carlos\",\n \"lastName\": \"Solarte\",\n \"avatarUrl\": \"users/default.png\"\n }\n }\n}" tags: - Eventos security: [] parameters: - in: path name: event_id description: 'The ID of the event.' example: 1 required: true schema: type: integer - in: path name: event description: 'El ID del evento.' example: '1' required: true schema: type: string /api/companies-filters: get: summary: 'Listar y Filtrar Compañías' operationId: listarYFiltrarCompaas description: "Muestra una lista paginada de compañías.\nPermite múltiples filtros y opciones de ordenamiento para descubrir compañías." parameters: - in: query name: label description: 'Filtrar compañías por el nombre de una etiqueta.' example: Restaurante required: false schema: type: string description: 'Filtrar compañías por el nombre de una etiqueta.' example: Restaurante nullable: false - in: query name: has_active_events description: 'Filtrar compañías que tengan al menos un evento activo.' example: true required: false schema: type: boolean description: 'Filtrar compañías que tengan al menos un evento activo.' example: true nullable: false - in: query name: sort_by description: "Ordenar los resultados. Opciones: 'rating' (mejor a peor calificada)." example: rating required: false schema: type: string description: "Ordenar los resultados. Opciones: 'rating' (mejor a peor calificada)." example: rating nullable: false responses: 200: description: '' content: text/plain: schema: type: string example: "{\n \"data\": [\n {\n \"id\": 1,\n \"name\": \"Company 1\",\n \"logoUrl\": null,\n \"description\": \"This company.\",\n \"phone\": \"3121231230\",\n \"catalogUrl\": null,\n \"schedule\": null,\n \"address\": null,\n \"city\": \"Pasto\",\n \"location\": \"1.2136,-77.2793\",\n \"gameRoomUrl\": null,\n\_ \_ \_ \_\"hasActiveEvents\": true\n }\n ]\n}" 404: description: '' content: application/json: schema: type: object example: message: 'No query results for model [App\Models\Company] 99' properties: message: type: string example: 'No query results for model [App\Models\Company] 99' tags: - Filtros security: [] /api/companies-filters/nearby: get: summary: 'Buscar compañías cercanas' operationId: buscarCompaasCercanas description: 'Este endpoint permite buscar compañías cercanas a una ubicación geográfica utilizando latitud, longitud y un radio (en km).' parameters: - in: query name: lat description: 'float Latitud actual del usuario.' example: '-12.0464' required: true schema: type: string description: 'float Latitud actual del usuario.' example: '-12.0464' nullable: false - in: query name: lng description: 'float Longitud actual del usuario.' example: '-77.0428' required: true schema: type: string description: 'float Longitud actual del usuario.' example: '-77.0428' nullable: false - in: query name: radius description: 'Radio de búsqueda en kilómetros (por defecto: 25 km). Mínimo: 1, máximo: 100.' example: 10.0 required: false schema: type: number description: 'Radio de búsqueda en kilómetros (por defecto: 25 km). Mínimo: 1, máximo: 100.' example: 10.0 nullable: false responses: 200: description: '' content: text/plain: schema: type: string example: "{\n\"data\": [\n {\n \"id\": 1,\n \"name\": \"Arcade Central Pasto\",\n \"logoUrl\": null,\n \"description\": \"La mejor sala de juegos de Nariño.\",\n \"phone\": null,\n \"catalogUrl\": null,\n \"schedule\": null,\n \"address\": null,\n \"city\": \"Pasto\",\n \"location\": \"1.213615,-77.279343\",\n \"gameRoomUrl\": null,\n \"distance\": 0.01\n },\n]}" tags: - Filtros requestBody: required: true content: application/json: schema: type: object properties: lat: type: number description: 'Must be between -90 and 90.' example: -89 nullable: false lng: type: number description: 'Must be between -180 and 180.' example: -180 nullable: false radius: type: number description: 'Must be at least 1. Must not be greater than 100.' example: 16 nullable: true required: - lat - lng security: [] '/api/companies-filters/{company_id}/average-rating': get: summary: 'Obtener calificación compañia' operationId: obtenerCalificacinCompaia description: 'Calcula y devuelve la calificación promedio (de 1 a 5) y el número total de reseñas para una compañía específica.' parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: data: company_id: 1 average_rating: '4.3' review_count: 15 properties: data: type: object properties: company_id: type: integer example: 1 average_rating: type: string example: '4.3' review_count: type: integer example: 15 404: description: '' content: application/json: schema: type: object example: message: 'No query results for model [App\Models\Company] 99' properties: message: type: string example: 'No query results for model [App\Models\Company] 99' tags: - Filtros security: [] parameters: - in: path name: company_id description: 'El ID de la compañía.' example: '1' required: true schema: type: string /api/events-filters: get: summary: 'Listar y filtrar Eventos' operationId: listarYFiltrarEventos description: "Muestra una lista paginada de todos los eventos que están actualmente activos.\nPermite filtrar por ciudad, compañía o por los minijuegos incluidos en el evento.\nLos eventos se ordenan por los más recientes primero." parameters: - in: query name: city description: 'Filtrar eventos por ciudad (búsqueda parcial).' example: Pasto required: false schema: type: string description: 'Filtrar eventos por ciudad (búsqueda parcial).' example: Pasto nullable: false - in: query name: company_id description: 'Filtrar eventos por el ID de la compañía organizadora.' example: 1 required: false schema: type: integer description: 'Filtrar eventos por el ID de la compañía organizadora.' example: 1 nullable: false - in: query name: minigame_id description: 'Filtrar eventos que incluyan un minijuego específico por su ID.' example: 2 required: false schema: type: integer description: 'Filtrar eventos que incluyan un minijuego específico por su ID.' example: 2 nullable: false responses: 200: description: '' content: text/plain: schema: type: string example: "{\n\"data\": [\n {\n \"id\": 1,\n \"description\": \"Gran Torneo de Verano\",\n \"duration\": \"7 days\",\n \"isActive\": true,\n \"city\": \"Pasto\",\n \"company\": {\n \"id\": 1,\n \"name\": \"Arcade Central Pasto\"\n },\n \"minigames\": [\n {\n \"id\": 1,\n \"name\": \"Space Invaders\"\n },\n {\n \"id\": 2,\n \"name\": \"Tetris Challenge\"\n }\n ]\n }\n],\n}" tags: - Filtros security: [] '/api/minigames/{minigame_id}/play': post: summary: 'Iniciar Partida' operationId: iniciarPartida description: "Valida si el usuario puede pagar el costo del minijuego (con monedas o tickets)\ny resta el saldo correspondiente, registrando la transacción." parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: message: '¡Partida iniciada! Buena suerte.' properties: message: type: string example: '¡Partida iniciada! Buena suerte.' 402: description: '' content: application/json: schema: type: object example: message: 'Saldo de monedas insuficiente.' properties: message: type: string example: 'Saldo de monedas insuficiente.' 422: description: '' content: application/json: schema: type: object example: message: 'Este minijuego no está disponible en el evento especificado.' properties: message: type: string example: 'Este minijuego no está disponible en el evento especificado.' tags: - Juegos requestBody: required: true content: application/json: schema: type: object properties: payment_method: type: string description: "El método de pago. Opciones: 'coins', 'tickets'." example: '"coins"' nullable: false event_id: type: integer description: 'El ID del evento en el que se está jugando.' example: 1 nullable: false required: - payment_method - event_id security: [] parameters: - in: path name: minigame_id description: 'The ID of the minigame.' example: 1 required: true schema: type: integer - in: path name: minigame description: 'El ID del minijuego al que se quiere jugar.' example: '1' required: true schema: type: string /api/scores: post: summary: 'Guardar Puntuación' operationId: guardarPuntuacin description: 'Guarda la puntuación final del usuario para un minijuego en un evento específico.' parameters: [] responses: 201: description: '' content: application/json: schema: type: object example: message: 'Puntuación guardada exitosamente' properties: message: type: string example: 'Puntuación guardada exitosamente' tags: - Juegos requestBody: required: true content: application/json: schema: type: object properties: minigame_id: type: integer description: 'El ID del minijuego.' example: 1 nullable: false event_id: type: integer description: 'El ID del evento.' example: 1 nullable: false score: type: integer description: 'La puntuación obtenida.' example: 15000 nullable: false required: - minigame_id - event_id - score '/api/companies-reviews/{company_id}/reviews': get: summary: 'Listar Reseñas de una Compañía' operationId: listarReseasDeUnaCompaa description: "Muestra una lista paginada de todas las reseñas para una compañía específica.\nLas reseñas se ordenan por las más recientes primero." parameters: [] responses: 200: description: '' content: text/plain: schema: type: string example: "{\n \"data\": [\n {\n \"id\": 1,\n \"rating\": 5,\n \"comment\": \"¡El mejor lugar!\",\n \"user\": {\n \"id\": 2,\n \"name\": \"Carlos Solarte\"\n }\n }\n ],\n}" tags: - 'Reseñas (Reviews)' security: [] post: summary: 'Crear una Nueva Reseña' operationId: crearUnaNuevaResea description: "Permite al usuario autenticado publicar una nueva reseña para una compañía.\nUn usuario solo puede publicar una reseña por compañía." parameters: [] responses: 201: description: '' content: application/json: schema: type: object example: data: id: 2 rating: 5 comment: 'Me encantó el servicio.' user: id: 1 name: 'Ana Rivera' properties: data: type: object properties: id: type: integer example: 2 rating: type: integer example: 5 comment: type: string example: 'Me encantó el servicio.' user: type: object properties: id: type: integer example: 1 name: type: string example: 'Ana Rivera' 422: description: '' content: application/json: schema: type: object example: message: 'Ya has calificado a esta compañía.' errors: company_id: - 'Ya has calificado a esta compañía.' properties: message: type: string example: 'Ya has calificado a esta compañía.' errors: type: object properties: company_id: type: array example: - 'Ya has calificado a esta compañía.' items: type: string tags: - 'Reseñas (Reviews)' requestBody: required: true content: application/json: schema: type: object properties: rating: type: integer description: 'La calificación (de 1 a 5 estrellas).' example: 5 nullable: false comment: type: string description: 'El comentario (opcional).' example: '"Me encantó el servicio."' nullable: true required: - rating security: [] put: summary: 'Actualizar una Reseña' operationId: actualizarUnaResea description: "Permite al usuario autenticado actualizar su propia reseña para una compañía.\nEl usuario solo puede modificar la calificación y/o el comentario." parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: data: id: 1 rating: 4 comment: 'Lo he pensado mejor, el servicio fue bueno.' user: id: 1 name: 'Ana Rivera' properties: data: type: object properties: id: type: integer example: 1 rating: type: integer example: 4 comment: type: string example: 'Lo he pensado mejor, el servicio fue bueno.' user: type: object properties: id: type: integer example: 1 name: type: string example: 'Ana Rivera' 404: description: '' content: application/json: schema: type: object example: message: 'No se encontró una reseña tuya para esta compañía.' properties: message: type: string example: 'No se encontró una reseña tuya para esta compañía.' tags: - 'Reseñas (Reviews)' requestBody: required: false content: application/json: schema: type: object properties: rating: type: integer description: 'La nueva calificación (de 1 a 5 estrellas).' example: 4 nullable: false comment: type: string description: 'El nuevo comentario (opcional).' example: '"Lo he pensado mejor, el servicio fue bueno."' nullable: true security: [] parameters: - in: path name: company_id description: 'The ID of the company.' example: 1 required: true schema: type: integer - in: path name: company description: 'El ID de la compañía.' example: '1' required: true schema: type: string '/api/reviews-react/{review_id}': post: summary: 'Reaccionar a una Reseña (Like/Dislike)' operationId: reaccionarAUnaReseaLikeDislike description: 'Permite al usuario dar "me gusta" o "no me gusta" a una reseña.' parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: message: 'Reacción actualizada.' new_likes: 1 new_dislikes: 0 properties: message: type: string example: 'Reacción actualizada.' new_likes: type: integer example: 1 new_dislikes: type: integer example: 0 tags: - 'Reseñas (Reviews)' requestBody: required: true content: application/json: schema: type: object properties: reaction: type: string description: "El tipo de reacción. Opciones: 'like', 'dislike'." example: '"like"' nullable: false required: - reaction security: [] parameters: - in: path name: review_id description: 'The ID of the review.' example: 1 required: true schema: type: integer - in: path name: review description: 'El ID de la reseña a la que reaccionar.' example: '1' required: true schema: type: string /api/match/create: post: summary: 'Crear una nueva sala de juego.' operationId: crearUnaNuevaSalaDeJuego description: "Este endpoint permite crear una sala automáticamente con un nombre único\ny asignar al usuario autenticado como propietario. La sala puede ser\npública o privada según el parámetro enviado." parameters: [] responses: 201: description: '' content: text/plain: schema: type: string example: "{\n \"status\": \"success\",\n \"data\": {\n \"id\": 1,\n \"name\": \"Room-ABCD12\",\n \"owner_id\": 5,\n \"status\": \"creada\",\n \"privacidad\": \"publica\",\n \"created_at\": \"2025-10-08T16:41:12.000000Z\",\n \"updated_at\": \"2025-10-08T16:41:12.000000Z\"\n }\n} \"La respuesta incluye los datos completos de la sala creada, mostrando su estado inicial, privacidad y propietario.\"" 401: description: '' content: text/plain: schema: type: string example: "{\n \"message\": \"Unauthenticated.\"\n} \"Se retorna cuando el usuario no está autenticado y no puede crear la sala.\"" tags: - Rooms requestBody: required: true content: application/json: schema: type: object properties: privacidad: type: string description: 'Define la privacidad de la sala. Puede ser "publica" o "privada".' example: publica nullable: false required: - privacidad '/api/match/join/{room_name}': post: summary: 'Unirse a una sala privada.' operationId: unirseAUnaSalaPrivada description: '' parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: status: success data: room_name: Room-ABCD12 users: - id: 1 name: Harvey - id: 2 name: Pablo user_count: 2 properties: status: type: string example: success data: type: object properties: room_name: type: string example: Room-ABCD12 users: type: array example: - id: 1 name: Harvey - id: 2 name: Pablo items: type: object properties: id: type: integer example: 1 name: type: string example: Harvey user_count: type: integer example: 2 403: description: '' content: application/json: schema: type: object example: status: error message: 'La sala ya está completa.' properties: status: type: string example: error message: type: string example: 'La sala ya está completa.' 404: description: '' content: application/json: schema: type: object example: status: error message: 'Sala no encontrada.' properties: status: type: string example: error message: type: string example: 'Sala no encontrada.' 423: description: '' content: application/json: schema: type: object example: status: error message: 'Otro usuario está uniéndose a la sala, intenta de nuevo.' properties: status: type: string example: error message: type: string example: 'Otro usuario está uniéndose a la sala, intenta de nuevo.' tags: - Rooms parameters: - in: path name: room_name description: 'Nombre de la sala a la que el usuario quiere unirse.' example: Room-ABCD12 required: true schema: type: string /api/match/joinramdon: post: summary: 'Unirse a una sala pública de forma aleatoria.' operationId: unirseAUnaSalaPblicaDeFormaAleatoria description: "Busca una sala pública con espacio disponible (máximo 2 jugadores).\nSi existe, el usuario se une a ella.\nSi no existe, se crea una nueva sala pública y el usuario se convierte en su propietario." parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: status: success message: 'Te uniste a una sala pública existente.' data: room_name: Room-XYZ123 users: - id: 5 first_name: Harvey - id: 7 first_name: Carlos user_count: 2 properties: status: type: string example: success message: type: string example: 'Te uniste a una sala pública existente.' data: type: object properties: room_name: type: string example: Room-XYZ123 users: type: array example: - id: 5 first_name: Harvey - id: 7 first_name: Carlos items: type: object properties: id: type: integer example: 5 first_name: type: string example: Harvey user_count: type: integer example: 2 201: description: '' content: application/json: schema: type: object example: status: created message: 'No había sala disponible, se creó una nueva pública.' data: room_name: Room-ABCD12 users: - id: 5 first_name: Harvey user_count: 1 properties: status: type: string example: created message: type: string example: 'No había sala disponible, se creó una nueva pública.' data: type: object properties: room_name: type: string example: Room-ABCD12 users: type: array example: - id: 5 first_name: Harvey items: type: object properties: id: type: integer example: 5 first_name: type: string example: Harvey user_count: type: integer example: 1 423: description: '' content: application/json: schema: type: object example: status: error message: 'Otro usuario está uniéndose a una sala, intenta de nuevo.' properties: status: type: string example: error message: type: string example: 'Otro usuario está uniéndose a una sala, intenta de nuevo.' tags: - Rooms '/api/match/start/{room_name}': post: summary: 'Iniciar una partida.' operationId: iniciarUnaPartida description: "Verifica si el usuario pertenece a la sala y si hay al menos 2 jugadores\npara poder iniciar la partida , la idea general es que cuando se cree la sala o se una a la sala ramdon o privada lo pase al star para ver el contrincante." parameters: [] responses: 200: description: '' content: application/json: schema: oneOf: - description: '' type: object example: status: incompleto users: - id: 5 first_name: Carlos message: 'Esperando jugadores.' properties: status: type: string example: incompleto users: type: array example: - id: 5 first_name: Carlos items: type: object properties: id: type: integer example: 5 first_name: type: string example: Carlos message: type: string example: 'Esperando jugadores.' - description: '' type: object example: status: success message: 'Partida iniciada.' data: room_name: Room-ABCD12 users: - id: 5 first_name: Carlos - id: 6 first_name: Ana properties: status: type: string example: success message: type: string example: 'Partida iniciada.' data: type: object properties: room_name: type: string example: Room-ABCD12 users: type: array example: - id: 5 first_name: Carlos - id: 6 first_name: Ana items: type: object properties: id: type: integer example: 5 first_name: type: string example: Carlos 403: description: '' content: application/json: schema: type: object example: status: error message: 'No tienes acceso a esta sala.' properties: status: type: string example: error message: type: string example: 'No tienes acceso a esta sala.' 404: description: '' content: application/json: schema: type: object example: status: error message: 'Sala no encontrada.' properties: status: type: string example: error message: type: string example: 'Sala no encontrada.' tags: - Rooms parameters: - in: path name: room_name description: 'El nombre único de la sala.' example: Room-ABCD12 required: true schema: type: string '/api/match/deal/{room_name}': post: summary: 'Repartir cartas a un jugador en la sala.' operationId: repartirCartasAUnJugadorEnLaSala description: '' parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: status: success message: 'Cartas asignadas.' cards: - id: 12 name: 'Fuego Básico' element: fire power: 3 sprite_key: fire_basic win_effect: fire_blast lose_effect: smoke - id: 20 name: 'Agua Básica' element: water power: 2 sprite_key: water_basic win_effect: water_splash lose_effect: drowned properties: status: type: string example: success message: type: string example: 'Cartas asignadas.' cards: type: array example: - id: 12 name: 'Fuego Básico' element: fire power: 3 sprite_key: fire_basic win_effect: fire_blast lose_effect: smoke - id: 20 name: 'Agua Básica' element: water power: 2 sprite_key: water_basic win_effect: water_splash lose_effect: drowned items: type: object properties: id: type: integer example: 12 name: type: string example: 'Fuego Básico' element: type: string example: fire power: type: integer example: 3 sprite_key: type: string example: fire_basic win_effect: type: string example: fire_blast lose_effect: type: string example: smoke 403: description: '' content: application/json: schema: type: object example: status: error message: 'No tienes acceso a esta sala.' properties: status: type: string example: error message: type: string example: 'No tienes acceso a esta sala.' 404: description: '' content: application/json: schema: type: object example: status: error message: 'Sala no encontrada.' properties: status: type: string example: error message: type: string example: 'Sala no encontrada.' tags: - Rooms parameters: - in: path name: room_name description: 'Nombre único de la sala.' example: Room-ABCD12 required: true schema: type: string '/api/match/playcard/{room_name}': post: summary: 'Jugar una carta en la sala.' operationId: jugarUnaCartaEnLaSala description: "Permite al jugador enviar una carta durante una ronda activa.\nSi la carta es válida y aún no ha sido jugada, se marca como jugada y se le asigna una nueva carta al jugador.\nCuando ambos jugadores han jugado, la ronda se resuelve automáticamente." parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: status: success message: 'Carta enviada correctamente' new_card: id: 12 properties: status: type: string example: success message: type: string example: 'Carta enviada correctamente' new_card: type: object properties: id: type: integer example: 12 400: description: '' content: application/json: schema: oneOf: - description: '' type: object example: status: error message: 'No existe esa carta en la baraja o ya fue jugada' properties: status: type: string example: error message: type: string example: 'No existe esa carta en la baraja o ya fue jugada' - description: '' type: object example: status: error message: 'Ya jugaste tu carta en esta ronda.' properties: status: type: string example: error message: type: string example: 'Ya jugaste tu carta en esta ronda.' - description: '' type: object example: status: error message: 'No hay más cartas disponibles.' properties: status: type: string example: error message: type: string example: 'No hay más cartas disponibles.' 403: description: '' content: application/json: schema: type: object example: status: error message: 'No tienes acceso a esta sala.' properties: status: type: string example: error message: type: string example: 'No tienes acceso a esta sala.' 404: description: '' content: application/json: schema: type: object example: status: error message: 'Sala no encontrada.' properties: status: type: string example: error message: type: string example: 'Sala no encontrada.' tags: - Rooms requestBody: required: true content: application/json: schema: type: object properties: card_id: type: integer description: 'ID de la carta que el jugador desea jugar.' example: 5 nullable: false required: - card_id parameters: - in: path name: room_name description: 'Nombre único de la sala.' example: Room-OD9PHT94 required: true schema: type: string