# API Reference - Padel Pro Documentacion completa de los endpoints REST de la API de Padel Pro. ## Informacion General - **Base URL:** `http://localhost:3000/api` - **Autenticacion:** Basada en sesiones (NextAuth.js) - **Formato:** JSON - **Codificacion:** UTF-8 ### Codigos de Estado HTTP | Codigo | Descripcion | |--------|-------------| | 200 | Exito | | 201 | Recurso creado | | 400 | Solicitud invalida | | 401 | No autorizado | | 403 | Prohibido (sin permisos) | | 404 | Recurso no encontrado | | 409 | Conflicto (ej: duplicado) | | 500 | Error interno del servidor | ### Roles de Usuario | Rol | Descripcion | Permisos | |-----|-------------|----------| | `SUPER_ADMIN` | Administrador del sistema | Acceso total | | `ORG_ADMIN` | Administrador de organizacion | Gestion completa de la organizacion | | `SITE_ADMIN` | Administrador de sede | Gestion de una sede especifica | | `RECEPTIONIST` | Recepcionista | Reservas, ventas, clientes | | `COACH` | Entrenador | Acceso limitado | --- ## Autenticacion ### Endpoints de NextAuth ``` GET/POST /api/auth/[...nextauth] ``` NextAuth maneja automaticamente los siguientes endpoints: | Ruta | Metodo | Descripcion | |------|--------|-------------| | `/api/auth/signin` | GET | Pagina de inicio de sesion | | `/api/auth/signout` | POST | Cerrar sesion | | `/api/auth/session` | GET | Obtener sesion actual | | `/api/auth/csrf` | GET | Token CSRF | | `/api/auth/providers` | GET | Proveedores disponibles | | `/api/auth/callback/:provider` | GET/POST | Callback de proveedor | --- ## Sedes (Sites) ### Listar Sedes ```http GET /api/sites ``` **Autenticacion:** Requerida **Respuesta Exitosa (200):** ```json [ { "id": "clxyz123", "name": "Padel Club Centro", "slug": "padel-club-centro", "address": "Calle Principal 123", "phone": "+34 600 000 000", "email": "centro@padelclub.com", "timezone": "Europe/Madrid", "openTime": "08:00", "closeTime": "22:00", "courtCount": 6 } ] ``` --- ## Canchas (Courts) ### Listar Canchas ```http GET /api/courts ``` **Autenticacion:** Requerida **Parametros de Query:** | Parametro | Tipo | Descripcion | |-----------|------|-------------| | `siteId` | string | Filtrar por sede | **Respuesta Exitosa (200):** ```json [ { "id": "clxyz456", "name": "Cancha 1", "type": "INDOOR", "status": "AVAILABLE", "pricePerHour": 30.00, "description": "Cancha cubierta con iluminacion LED", "features": ["LED", "Cristal"], "displayOrder": 1, "isActive": true, "site": { "id": "clxyz123", "name": "Padel Club Centro", "openTime": "08:00", "closeTime": "22:00" } } ] ``` ### Crear Cancha ```http POST /api/courts ``` **Autenticacion:** Requerida **Roles permitidos:** `SUPER_ADMIN`, `SITE_ADMIN` **Cuerpo de la Solicitud:** ```json { "siteId": "clxyz123", "name": "Cancha 7", "type": "OUTDOOR", "pricePerHour": 25.00, "description": "Cancha exterior", "features": ["Cesped artificial"], "displayOrder": 7 } ``` **Campos Requeridos:** `siteId`, `name`, `pricePerHour` **Respuesta Exitosa (201):** ```json { "id": "clxyz789", "name": "Cancha 7", "type": "OUTDOOR", "status": "AVAILABLE", "pricePerHour": 25.00, "isActive": true, "site": { ... } } ``` ### Obtener Cancha por ID ```http GET /api/courts/{id} ``` **Autenticacion:** Requerida **Respuesta Exitosa (200):** ```json { "id": "clxyz456", "name": "Cancha 1", "type": "INDOOR", "status": "AVAILABLE", "pricePerHour": 30.00, "site": { "id": "clxyz123", "name": "Padel Club Centro", "address": "Calle Principal 123", "phone": "+34 600 000 000" } } ``` ### Actualizar Cancha ```http PUT /api/courts/{id} ``` **Autenticacion:** Requerida **Roles permitidos:** `SUPER_ADMIN`, `SITE_ADMIN` **Cuerpo de la Solicitud (todos los campos opcionales):** ```json { "name": "Cancha 1 VIP", "type": "INDOOR", "status": "MAINTENANCE", "pricePerHour": 35.00, "description": "Cancha premium renovada", "features": ["LED", "Cristal", "Climatizada"], "isActive": true } ``` ### Eliminar Cancha ```http DELETE /api/courts/{id} ``` **Autenticacion:** Requerida **Roles permitidos:** `SUPER_ADMIN`, `SITE_ADMIN` **Respuesta Exitosa (200):** ```json { "message": "Court deleted successfully" } ``` ### Obtener Disponibilidad ```http GET /api/courts/{id}/availability ``` **Autenticacion:** Requerida **Parametros de Query:** | Parametro | Tipo | Descripcion | |-----------|------|-------------| | `date` | string | Fecha en formato YYYY-MM-DD | --- ## Reservas (Bookings) ### Listar Reservas ```http GET /api/bookings ``` **Autenticacion:** Requerida **Parametros de Query:** | Parametro | Tipo | Descripcion | |-----------|------|-------------| | `siteId` | string | Filtrar por sede | | `date` | string | Filtrar por fecha (YYYY-MM-DD) | | `status` | string | PENDING, CONFIRMED, CANCELLED, COMPLETED, NO_SHOW | | `clientId` | string | Filtrar por cliente | | `courtId` | string | Filtrar por cancha | **Respuesta Exitosa (200):** ```json [ { "id": "clxyz001", "startTime": "2024-01-15T10:00:00.000Z", "endTime": "2024-01-15T11:30:00.000Z", "status": "CONFIRMED", "paymentType": "CARD", "totalPrice": 45.00, "paidAmount": 45.00, "notes": null, "playerNames": ["Juan", "Maria", "Pedro", "Ana"], "court": { "id": "clxyz456", "name": "Cancha 1", "type": "INDOOR" }, "client": { "id": "clxyz100", "firstName": "Juan", "lastName": "Garcia", "email": "juan@email.com", "phone": "+34 600 111 222" }, "site": { "id": "clxyz123", "name": "Padel Club Centro" } } ] ``` ### Crear Reserva ```http POST /api/bookings ``` **Autenticacion:** Requerida **Cuerpo de la Solicitud:** ```json { "courtId": "clxyz456", "clientId": "clxyz100", "startTime": "2024-01-15T10:00:00.000Z", "endTime": "2024-01-15T11:30:00.000Z", "paymentType": "card", "notes": "Reserva para cumpleanos", "participants": [ { "name": "Juan" }, { "name": "Maria" }, { "name": "Pedro" }, { "name": "Ana" } ] } ``` **Respuesta Exitosa (201):** ```json { "id": "clxyz002", "startTime": "2024-01-15T10:00:00.000Z", "endTime": "2024-01-15T11:30:00.000Z", "status": "PENDING", "totalPrice": 45.00, "paidAmount": 0.00, "court": { ... }, "client": { ... } } ``` **Errores Comunes:** - `409`: Ya existe una reserva en ese horario - `404`: Cancha o cliente no encontrado - `400`: La cancha no esta disponible ### Obtener Reserva por ID ```http GET /api/bookings/{id} ``` ### Actualizar Reserva ```http PUT /api/bookings/{id} ``` **Cuerpo de la Solicitud:** ```json { "status": "CONFIRMED", "notes": "Cliente confirmado por telefono", "playerNames": ["Juan", "Maria", "Pedro", "Ana"] } ``` ### Cancelar Reserva ```http DELETE /api/bookings/{id} ``` **Cuerpo Opcional:** ```json { "cancelReason": "Cliente solicito cancelacion" } ``` ### Registrar Pago de Reserva ```http POST /api/bookings/{id}/pay ``` **Cuerpo de la Solicitud:** ```json { "amount": 45.00, "paymentType": "CARD", "reference": "TRX-123456" } ``` --- ## Clientes (Clients) ### Listar Clientes ```http GET /api/clients ``` **Autenticacion:** Requerida **Parametros de Query:** | Parametro | Tipo | Descripcion | |-----------|------|-------------| | `search` | string | Buscar por nombre, email o telefono | | `isActive` | boolean | Filtrar por estado activo | | `limit` | number | Limite de resultados (max 100) | | `offset` | number | Desplazamiento para paginacion | **Respuesta Exitosa (200):** ```json { "data": [ { "id": "clxyz100", "firstName": "Juan", "lastName": "Garcia", "email": "juan@email.com", "phone": "+34 600 111 222", "level": "INTERMEDIATE", "tags": ["VIP", "Torneo"], "isActive": true, "createdAt": "2024-01-01T00:00:00.000Z", "memberships": [ { "id": "clxyz200", "status": "ACTIVE", "remainingHours": 8, "endDate": "2024-06-01T00:00:00.000Z", "plan": { "id": "clxyz300", "name": "Plan Premium", "discountPercent": 20 } } ], "_count": { "bookings": 15 } } ], "pagination": { "total": 150, "limit": 50, "offset": 0, "hasMore": true } } ``` ### Crear Cliente ```http POST /api/clients ``` **Cuerpo de la Solicitud:** ```json { "firstName": "Maria", "lastName": "Lopez", "email": "maria@email.com", "phone": "+34 600 333 444", "dateOfBirth": "1990-05-15", "address": "Calle Nueva 45", "notes": "Prefiere canchas interiores", "tags": ["Principiante"], "skillLevel": "BEGINNER", "emergencyContact": { "name": "Pedro Lopez", "phone": "+34 600 555 666" } } ``` **Campos Requeridos:** `firstName`, `lastName` ### Obtener Cliente por ID ```http GET /api/clients/{id} ``` ### Actualizar Cliente ```http PUT /api/clients/{id} ``` ### Obtener Membresia del Cliente ```http GET /api/clients/{id}/membership ``` --- ## Productos (Products) ### Listar Productos ```http GET /api/products ``` **Autenticacion:** Requerida **Parametros de Query:** | Parametro | Tipo | Descripcion | |-----------|------|-------------| | `siteId` | string | Filtrar por sede | | `categoryId` | string | Filtrar por categoria | | `search` | string | Buscar por nombre | | `isActive` | boolean | Solo productos activos | **Respuesta Exitosa (200):** ```json [ { "id": "clxyz400", "name": "Pelotas HEAD Pro", "description": "Bote de 3 pelotas", "sku": "BALL-HEAD-001", "price": 6.50, "costPrice": 4.00, "stock": 50, "minStock": 10, "trackStock": true, "image": null, "isActive": true, "lowStock": false, "category": { "id": "clxyz500", "name": "Pelotas", "description": "Pelotas de padel" } } ] ``` ### Crear Producto ```http POST /api/products ``` **Autenticacion:** Requerida **Roles permitidos:** `SUPER_ADMIN`, `ORG_ADMIN`, `SITE_ADMIN` **Cuerpo de la Solicitud:** ```json { "siteId": "clxyz123", "categoryId": "clxyz500", "name": "Overgrip Wilson", "description": "Pack de 3 overgrips", "sku": "GRIP-WILSON-001", "price": 8.00, "costPrice": 5.50, "stock": 30, "minStock": 5, "trackStock": true } ``` ### Actualizar Stock ```http PATCH /api/products/{id}/stock ``` **Cuerpo de la Solicitud:** ```json { "adjustment": 10, "reason": "Reposicion de inventario" } ``` ### Listar Categorias ```http GET /api/products/categories ``` --- ## Ventas (Sales) ### Listar Ventas ```http GET /api/sales ``` **Autenticacion:** Requerida **Parametros de Query:** | Parametro | Tipo | Descripcion | |-----------|------|-------------| | `siteId` | string | Filtrar por sede | | `startDate` | string | Fecha inicio (YYYY-MM-DD) | | `endDate` | string | Fecha fin (YYYY-MM-DD) | | `clientId` | string | Filtrar por cliente | | `createdBy` | string | Filtrar por vendedor | **Respuesta Exitosa (200):** ```json [ { "id": "clxyz600", "subtotal": 25.00, "discount": 0.00, "tax": 5.25, "total": 30.25, "paymentType": "CASH", "notes": null, "createdAt": "2024-01-15T14:30:00.000Z", "items": [ { "id": "clxyz601", "quantity": 2, "unitPrice": 6.50, "subtotal": 13.00, "product": { "id": "clxyz400", "name": "Pelotas HEAD Pro", "sku": "BALL-HEAD-001" } } ], "payments": [ { "id": "clxyz602", "amount": 30.25, "paymentType": "CASH", "reference": null } ], "client": null, "createdBy": { "id": "clxyz700", "firstName": "Ana", "lastName": "Martinez" }, "cashRegister": { "id": "clxyz800", "site": { "id": "clxyz123", "name": "Padel Club Centro" } } } ] ``` ### Crear Venta ```http POST /api/sales ``` **Cuerpo de la Solicitud:** ```json { "siteId": "clxyz123", "clientId": "clxyz100", "items": [ { "productId": "clxyz400", "quantity": 2, "price": 6.50 }, { "productId": "clxyz401", "quantity": 1, "price": 12.00 } ], "payments": [ { "amount": 25.00, "method": "CASH" } ], "discount": 0, "tax": 0, "notes": "Venta rapida" } ``` **Nota:** Requiere caja registradora abierta si hay pago en efectivo. --- ## Caja Registradora (Cash Register) ### Obtener Estado de Caja ```http GET /api/cash-register ``` **Parametros de Query:** | Parametro | Tipo | Descripcion | |-----------|------|-------------| | `siteId` | string | Sede | | `status` | string | `open`, `closed`, o `all` | | `date` | string | Fecha especifica (YYYY-MM-DD) | **Respuesta Exitosa (200) - Caja Abierta:** ```json { "id": "clxyz800", "openingAmount": 100.00, "closingAmount": null, "expectedAmount": null, "difference": null, "openedAt": "2024-01-15T08:00:00.000Z", "closedAt": null, "site": { "id": "clxyz123", "name": "Padel Club Centro" }, "user": { "id": "clxyz700", "firstName": "Ana", "lastName": "Martinez" }, "paymentBreakdown": { "CASH": 250.00, "CARD": 180.00 }, "totalCashSales": 250.00, "expectedAmount": 350.00, "_count": { "sales": 12, "payments": 15 } } ``` ### Abrir Caja ```http POST /api/cash-register ``` **Cuerpo de la Solicitud:** ```json { "siteId": "clxyz123", "openingAmount": 100.00 } ``` ### Cerrar Caja ```http PUT /api/cash-register/{id} ``` **Cuerpo de la Solicitud:** ```json { "closingAmount": 345.50, "notes": "Cuadre correcto" } ``` ### Obtener Transacciones ```http GET /api/cash-register/{id}/transactions ``` --- ## Torneos (Tournaments) ### Listar Torneos ```http GET /api/tournaments ``` **Parametros de Query:** | Parametro | Tipo | Descripcion | |-----------|------|-------------| | `siteId` | string | Filtrar por sede | | `status` | string | DRAFT, REGISTRATION_OPEN, IN_PROGRESS, COMPLETED, CANCELLED | | `startDate` | string | Fecha inicio del rango | | `endDate` | string | Fecha fin del rango | **Respuesta Exitosa (200):** ```json [ { "id": "clxyz900", "name": "Torneo de Verano 2024", "description": "Torneo amateur categoria B", "type": "BRACKET", "status": "REGISTRATION_OPEN", "startDate": "2024-07-15T09:00:00.000Z", "endDate": "2024-07-16T20:00:00.000Z", "maxPlayers": 32, "entryFee": 25.00, "site": { "id": "clxyz123", "name": "Padel Club Centro" }, "_count": { "inscriptions": 18, "matches": 0 } } ] ``` ### Crear Torneo ```http POST /api/tournaments ``` **Roles permitidos:** `SUPER_ADMIN`, `ORG_ADMIN`, `SITE_ADMIN` **Cuerpo de la Solicitud:** ```json { "siteId": "clxyz123", "name": "Torneo de Primavera", "description": "Torneo para socios", "date": "2024-04-20T09:00:00.000Z", "endDate": "2024-04-21T20:00:00.000Z", "type": "SINGLE_ELIMINATION", "category": "B", "maxTeams": 16, "price": 20.00 } ``` ### Obtener Torneo por ID ```http GET /api/tournaments/{id} ``` ### Actualizar Torneo ```http PUT /api/tournaments/{id} ``` ### Listar Inscripciones ```http GET /api/tournaments/{id}/inscriptions ``` **Respuesta Exitosa (200):** ```json [ { "id": "clxyzabc", "teamName": "Los Campeones", "seedNumber": 1, "isPaid": true, "paidAmount": 25.00, "registeredAt": "2024-01-10T12:00:00.000Z", "client": { "id": "clxyz100", "firstName": "Juan", "lastName": "Garcia", "level": "ADVANCED" }, "partner": { "id": "clxyz101", "firstName": "Pedro", "lastName": "Martinez", "level": "ADVANCED" } } ] ``` ### Inscribir Equipo ```http POST /api/tournaments/{id}/inscriptions ``` **Cuerpo de la Solicitud:** ```json { "player1Id": "clxyz100", "player2Id": "clxyz101", "teamName": "Los Campeones" } ``` ### Generar Bracket ```http POST /api/tournaments/{id}/generate-bracket ``` ### Actualizar Resultado de Partido ```http PUT /api/tournaments/{id}/matches/{matchId} ``` **Cuerpo de la Solicitud:** ```json { "score1": "6-4", "score2": "6-3", "winnerId": "clxyzabc" } ``` --- ## Planes de Membresia (Membership Plans) ### Listar Planes ```http GET /api/membership-plans ``` **Parametros de Query:** | Parametro | Tipo | Descripcion | |-----------|------|-------------| | `includeInactive` | boolean | Incluir planes inactivos | **Respuesta Exitosa (200):** ```json [ { "id": "clxyz300", "name": "Plan Premium", "description": "Acceso completo con beneficios exclusivos", "price": 99.00, "durationMonths": 1, "courtHours": 10, "discountPercent": 20, "benefits": ["Reserva anticipada", "Descuento en tienda"], "isActive": true, "subscriberCount": 45, "benefitsSummary": { "freeHours": 10, "bookingDiscount": 20, "extraBenefits": ["Reserva anticipada", "Descuento en tienda"] } } ] ``` ### Crear Plan ```http POST /api/membership-plans ``` **Roles permitidos:** `SUPER_ADMIN`, `ORG_ADMIN` **Cuerpo de la Solicitud:** ```json { "name": "Plan Basico", "description": "Plan de entrada", "price": 29.00, "durationMonths": 1, "freeHours": 2, "bookingDiscount": 10, "storeDiscount": 5, "extraBenefits": ["Newsletter exclusivo"] } ``` ### Actualizar Plan ```http PUT /api/membership-plans/{id} ``` --- ## Membresias (Memberships) ### Listar Membresias ```http GET /api/memberships ``` **Parametros de Query:** | Parametro | Tipo | Descripcion | |-----------|------|-------------| | `status` | string | ACTIVE, EXPIRED, CANCELLED, SUSPENDED | | `planId` | string | Filtrar por plan | | `search` | string | Buscar por nombre/email del cliente | | `expiring` | boolean | Solo proximas a vencer (7 dias) | | `limit` | number | Limite de resultados | | `offset` | number | Desplazamiento | **Respuesta Exitosa (200):** ```json { "data": [ { "id": "clxyz200", "startDate": "2024-01-01T00:00:00.000Z", "endDate": "2024-06-01T00:00:00.000Z", "status": "ACTIVE", "remainingHours": 8, "autoRenew": true, "notes": null, "plan": { "id": "clxyz300", "name": "Plan Premium", "price": 99.00, "durationMonths": 1, "courtHours": 10, "discountPercent": 20 }, "client": { "id": "clxyz100", "firstName": "Juan", "lastName": "Garcia", "email": "juan@email.com" }, "isExpiring": false, "daysUntilExpiry": 45, "benefitsSummary": { "freeHours": 10, "hoursRemaining": 8, "bookingDiscount": 20, "extraBenefits": [] } } ], "pagination": { "total": 150, "limit": 50, "offset": 0, "hasMore": true } } ``` ### Crear Membresia ```http POST /api/memberships ``` **Roles permitidos:** `SUPER_ADMIN`, `ORG_ADMIN`, `SITE_ADMIN`, `RECEPTIONIST` **Cuerpo de la Solicitud:** ```json { "clientId": "clxyz100", "planId": "clxyz300", "startDate": "2024-02-01T00:00:00.000Z", "endDate": "2024-03-01T00:00:00.000Z", "autoRenew": true, "notes": "Primera membresia del cliente" } ``` ### Renovar Membresia ```http POST /api/memberships/{id}/renew ``` **Cuerpo de la Solicitud:** ```json { "planId": "clxyz300", "paymentMethod": "CARD" } ``` --- ## Dashboard ### Obtener Estadisticas ```http GET /api/dashboard/stats ``` **Parametros de Query:** | Parametro | Tipo | Descripcion | |-----------|------|-------------| | `siteId` | string | Filtrar por sede | | `date` | string | Fecha especifica (YYYY-MM-DD) | **Respuesta Exitosa (200):** ```json { "stats": { "todayBookings": 24, "todayRevenue": 580.50, "occupancyRate": 75, "activeMembers": 145, "pendingBookings": 3, "upcomingTournaments": 2 }, "courtOccupancy": [ { "courtId": "clxyz456", "courtName": "Cancha 1", "availableHours": 14, "bookedHours": 11.5, "occupancyPercent": 82 } ], "recentBookings": [ { "id": "clxyz001", "startTime": "2024-01-15T10:00:00.000Z", "endTime": "2024-01-15T11:30:00.000Z", "status": "CONFIRMED", "court": { "id": "clxyz456", "name": "Cancha 1" }, "client": { "id": "clxyz100", "name": "Juan Garcia" } } ], "date": "2024-01-15" } ``` --- ## Errores Comunes ### Error de Autenticacion ```json { "error": "No autorizado" } ``` **Codigo:** 401 ### Error de Permisos ```json { "error": "Forbidden: Insufficient permissions" } ``` **Codigo:** 403 ### Recurso No Encontrado ```json { "error": "Court not found" } ``` **Codigo:** 404 ### Conflicto ```json { "error": "Ya existe una reserva en ese horario" } ``` **Codigo:** 409 ### Error de Validacion ```json { "error": "Invalid booking data", "details": { "courtId": ["Invalid court ID"], "startTime": ["Required"] } } ``` **Codigo:** 400 --- ## Notas Adicionales ### Paginacion Los endpoints que devuelven listas soportan paginacion mediante: - `limit`: Numero maximo de resultados (default: 50, max: 100) - `offset`: Numero de registros a saltar La respuesta incluye metadatos de paginacion: ```json { "data": [...], "pagination": { "total": 150, "limit": 50, "offset": 0, "hasMore": true } } ``` ### Filtrado por Sede La mayoria de endpoints filtran automaticamente por la sede del usuario si tiene una asignada. Para usuarios con acceso a multiples sedes, se puede especificar `siteId` en los parametros de query. ### Zonas Horarias Las fechas se manejan en UTC. Cada sede tiene configurada su zona horaria para mostrar correctamente los horarios de apertura/cierre.