39 KiB
API V2 — Documentación de endpoints
Base URL real: /2.0
Base URL mock: /2.0-mock (sin autenticación, datos de ejemplo)
Las rutas protegidas requieren el header
Authorization: Bearer {token}obtenido en/login. Todas las respuestas sonContent-Type: application/json.
Índice
- Auth
- People (abonado)
- Activities (actividades)
- Booking (reservas — app)
- Payments
- Wallet (monedero)
- Search (búsqueda)
- Members (socios — admin)
- Courses (cursos — admin)
- Bills (recibos — admin)
- Booking Admin (reservas — admin)
- Cash (caja — admin)
- Dayoff / Celebrations
- Remittance (remesas especiales)
- Inscriptions (preinscripciones)
- Admin Misc
- Printer
- Hash (público)
1. Auth
POST /login
Autentica al usuario y devuelve un token Bearer.
Body (form/JSON)
| Campo | Tipo | Descripción |
|---|---|---|
| string | Email del abonado | |
| password | string | Contraseña |
Respuesta 200
{
"access_token": "4Km9xQzLp2VnRtYwEoJbFsUcXgHdAiMkNlOqPrSvTu"
}
Respuesta 401
{
"message": "Contraseña incorrecta."
}
POST /forgot
Envía un email de recuperación de contraseña.
Body
| Campo | Tipo |
|---|---|
| string |
Respuesta 200
{
"error": "Se le ha enviado un email con instrucciones"
}
GET /logout 🔒
Cierra la sesión del usuario autenticado.
Respuesta 200
{
"logout": "ok"
}
2. People (abonado)
GET /people/me 🔒
Devuelve los datos del abonado autenticado.
Respuesta 200
{
"member": "00042",
"family": 1,
"first_name": "María",
"last_name": "García López",
"email": "maria@example.com",
"phone": "612345678",
"dni": "12345678A",
"birth_date": "15/03/1985",
"address": "Calle Mayor 12",
"city": "Madrid",
"zip": "28001",
"type": "FAMILIAR",
"balance": "12.50 €",
"is_unreg": false,
"b_paid": 0
}
POST /people/qr 🔒
Genera un código QR temporal (válido 15 minutos) para el abonado.
Body
| Campo | Tipo | Descripción |
|---|---|---|
| family | integer | (opcional) Número de familiar de la unidad |
Respuesta 200
{
"m": "00042",
"f": "01",
"code": "ABCDEF123456"
}
GET /people/card 🔒
Devuelve el carnet digital del abonado en base64.
Respuesta 200
{
"card": "iVBORw0KGgoAAAANSUhEUgAA...",
"me": 1
}
cardes una imagen PNG codificada en base64. Si no existe, devuelve"".
GET /people 🔒
Devuelve todos los miembros de la unidad familiar del abonado autenticado.
Respuesta 200
{
"people": [
{
"member": "00042",
"family": 1,
"first_name": "María",
"last_name": "García López",
"email": "maria@example.com",
"phone": "612345678",
"is_unreg": false
},
{
"member": "00042",
"family": 2,
"first_name": "Carlos",
"last_name": "García López",
"email": "carlos@example.com",
"phone": "623456789",
"is_unreg": false
}
],
"me": 1
}
meindica el número de familiar del usuario autenticado dentro del array.
3. Activities (actividades)
GET /activities 🔒
Devuelve el árbol completo de actividades/cursos disponibles.
Respuesta 200
[
{
"id": "001",
"name": "PÁDEL",
"levels": [
{
"id": "00101",
"name": "Iniciación",
"groups": [
{
"id": "0010101",
"name": "Lunes 18h",
"monitor": "Carlos",
"place": "Pista 1",
"hour": "L 18:00-19:00",
"price": "25.00"
},
{
"id": "0010102",
"name": "Miércoles 19h",
"monitor": "Carlos",
"place": "Pista 2",
"hour": "X 19:00-20:00",
"price": "25.00"
}
]
},
{
"id": "00102",
"name": "Avanzado",
"groups": [
{
"id": "0010201",
"name": "Martes 20h",
"monitor": "Ana",
"place": "Pista 3",
"hour": "M 20:00-21:00",
"price": "30.00"
}
]
}
]
},
{
"id": "002",
"name": "NATACIÓN",
"levels": [
{
"id": "00201",
"name": "Adultos",
"groups": [
{
"id": "0020101",
"name": "Lunes y Miércoles",
"monitor": "María",
"place": "Piscina",
"hour": "L-X 07:30-08:30",
"price": "35.00"
}
]
}
]
}
]
POST /activities 🔒
Preinscribe a un miembro de la familia en una actividad.
Body
| Campo | Tipo | Descripción |
|---|---|---|
| activity | string | Código de actividad (7 dígitos, ej. 0010101) |
| family | integer | Número de familiar |
| date_reg | string | Fecha de alta dd/mm/yyyy (opcional) |
| test_run | string | permanent o test |
| comment | string | Comentario / cuestionario de salud |
| privacy_policy | boolean | Aceptación política de privacidad |
| privacy_sports | boolean | Aceptación cláusula deportiva |
Respuesta 200 — éxito
{
"msg": "Su preinscripción está siendo procesada, cuando sea aceptado/a en el grupo le llegará un mensaje de confirmación.",
"error": "0"
}
Respuesta 200 — error
{
"msg": "El abonado/a ya está inscrito en la actividad",
"error": "3"
}
Códigos de error:
1actividad no permitida ·2ya en lista de espera ·3ya inscrito ·4error al guardar.
GET /activities/unreg 🔒
Devuelve las actividades e inscripciones de lista de espera de todos los miembros de la familia para solicitar bajas.
Respuesta 200
[
{
"fk_i_member_id": "00042",
"i_family": 1,
"s_first_name": "María",
"s_last_name": "García",
"courses": [
{ "i_activity": "0010101", "s_name": "Pádel Iniciación - Lunes 18h", "d_reg_date": "01/09/2025" },
{ "i_activity": "0030101", "s_name": "Fitness Mañanas", "d_reg_date": "15/09/2025" }
],
"waitlist": [
{ "i_activity": "0020101", "s_name": "Natación Adultos - L-X", "dt_date": "10/10/2025" }
]
}
]
POST /activities/unreg 🔒
Solicita la baja de actividades e inscripciones de lista de espera.
Body
| Campo | Tipo | Descripción |
|---|---|---|
| acs | object | Mapa "{family}-{activity}": 1 de actividades a dar de baja |
| wls | object | Mapa "{family}-{activity}": 1 de listas de espera |
| comment | string | Motivo / comentario |
| reason | string | Razón de baja |
| deftemp | string | definitiva o temporal |
Respuesta 200
{
"msg": "Su solicitud de baja ha sido procesada. Muchas gracias.",
"error": "0"
}
4. Booking (reservas — app)
GET /booking 🔒
Devuelve la rejilla de disponibilidad de pistas para una actividad y fecha.
Query params
| Param | Tipo | Ejemplo |
|---|---|---|
| actividad | integer | 1 |
| fecha | string | 18/03/2026 |
Respuesta 200
{
"columns": ["Horarios", "01", "02", "03", "04"],
"data": [
[
{ "row": 0, "hour_id": 1, "text": "0900-1000", "type": "H" },
{ "id": "", "paid": "", "hourText": "0900-1000", "courtText": "01", "hour": 1, "court": 0, "type": "E", "text": "" },
{ "id": 4521, "paid": 0, "hourText": "0900-1000", "courtText": "02", "hour": 1, "court": 1, "type": "R", "text": "R" },
{ "id": "", "paid": "", "hourText": "0900-1000", "courtText": "03", "hour": 1, "court": 2, "type": "E", "text": "" },
{ "id": "", "paid": "", "hourText": "0900-1000", "courtText": "04", "hour": 1, "court": 3, "type": "E", "text": "" }
]
],
"ac": { "pk_i_activity_id": 1, "s_name": "PÁDEL MURO", "i_courts": 4 },
"light": "1.00",
"extra": "1.50",
"amount": "6.00"
}
Tipos de celda:
Hcabecera horario ·Edisponible ·Rocupada (otro) ·Ituya sin pagar ·Ptuya pagada.
GET /booking/book/{id} 🔒
Devuelve el detalle de una reserva concreta.
Respuesta 200
{
"pk_i_id": 1234,
"fk_i_activity_id": 1,
"d_date": "2026-03-18",
"fk_i_court_id": 2,
"fk_i_hour": 3,
"s_hour": "1100-1200",
"fk_i_member_id": 42,
"fk_i_family": 1,
"b_paid": 0,
"s_source": "APP"
}
GET /booking/checkout/{id} 🔒
Devuelve los datos de pago para una reserva.
Respuesta 200
{
"booking_id": 1234,
"amount": "6.00",
"status": "pending",
"payment_url": "https://example.com/checkout/1234"
}
POST /booking 🔒
Realiza una reserva de pista.
Body
| Campo | Tipo | Descripción |
|---|---|---|
| fk_i_activity_id | integer | ID de actividad |
| hour | integer | ID de hora |
| d_date | string | Fecha dd/mm/yyyy |
| court | integer | Número de pista (base 0) |
| light | boolean | Solicitar luz |
Respuesta 200
{
"msg": "Reserva realizada correctamente",
"error": "0",
"id": 5678
}
POST /booking/cancel 🔒
Cancela una reserva existente.
Body
| Campo | Tipo |
|---|---|
| id | integer |
Respuesta 200
{
"msg": "Reserva cancelada correctamente",
"error": "0"
}
POST /booking/edit 🔒
Edita una reserva existente.
Body
| Campo | Tipo | Descripción |
|---|---|---|
| id | integer | ID de reserva |
| light | boolean | Activar/desactivar luz |
Respuesta 200
{
"msg": "Reserva editada correctamente",
"error": "0"
}
POST /booking/refresh 🔒
Refresca el estado de una reserva (actualiza pagos pendientes).
Respuesta 200
{
"msg": "ok",
"error": "0"
}
5. Payments
GET /payments 🔒
Devuelve el historial de pagos del abonado.
Respuesta 200
{
"payments": [
{
"id": 1,
"description": "Cuota mensual",
"amount": "35.00",
"date": "01/03/2026",
"status": "Pagado",
"type": "REMESA"
},
{
"id": 2,
"description": "Actividad pádel",
"amount": "25.00",
"date": "15/02/2026",
"status": "Pagado",
"type": "CAJA"
}
],
"error": "0"
}
6. Wallet (monedero)
GET /wallet 🔒
Devuelve el saldo y el historial de transacciones del monedero.
Respuesta 200
{
"transactions": [
{
"id": 1,
"concept": "Recarga monedero",
"amount": "20.00",
"date": "10/03/2026 09:15",
"balance": "20.00"
},
{
"id": 2,
"concept": "Pago reserva pádel",
"amount": "-6.00",
"date": "12/03/2026 18:32",
"balance": "14.00"
}
],
"balance": "14.00 €",
"error": "0"
}
7. Search (búsqueda)
GET /search 🔒
Búsqueda rápida de socios por nombre, apellido, número o DNI.
Query params
| Param | Tipo | Descripción |
|---|---|---|
| q | string | Término de búsqueda |
Respuesta 200
[
{ "id": "0004201", "member": "00042", "family": "01", "name": "García, María", "phone": "612345678" },
{ "id": "0012301", "member": "00123", "family": "01", "name": "García, Antonio", "phone": "623456789" }
]
GET /search/new 🔒
Búsqueda avanzada con filtros de tipo y estado.
Query params
| Param | Tipo | Valores |
|---|---|---|
| q | string | Término |
| type | string | all · FAMILIAR · INDIVIDUAL · SABIC |
| status | string | all · active · inactive |
Respuesta 200
{
"results": [
{
"id": "0004201",
"member": "00042",
"family": "01",
"name": "García, María",
"phone": "612345678",
"email": "maria@example.com",
"dni": "12345678A",
"type": "FAMILIAR",
"is_unreg": false,
"unreg_reason": "",
"b_paid": 0
}
],
"total": 1
}
GET /search/doorlog 🔒
Devuelve el log de accesos por torniquete de un abonado.
Query params
| Param | Tipo | Descripción |
|---|---|---|
| member | string | Número de socio (5 dígitos) |
| family | integer | Número de familiar (def. 1) |
| limit | integer | Máx. registros (def. 100) |
Respuesta 200
[
{
"pk_i_id": 1,
"fk_i_member_id": "00042",
"fk_i_people_id": 1,
"dt_date": "2026-03-15 09:23:11",
"s_source": "TORNIQUETE"
},
{
"pk_i_id": 2,
"fk_i_member_id": "00042",
"fk_i_people_id": 1,
"dt_date": "2026-03-14 18:45:02",
"s_source": "APP"
}
]
8. Members (socios — admin)
Todos los endpoints de esta sección requieren autenticación 🔒.
El objeto member tiene la siguiente estructura completa:
{
"pk_i_id": 42,
"d_reg_date": "2018-03-15",
"s_address": "Calle Mayor 12",
"s_city": "Madrid",
"s_zip": "28001",
"s_email": "socio@example.com",
"s_phone": "612345678",
"s_bank": "0049",
"s_bank_office": "1500",
"s_bank_sec_code": "42",
"s_bank_account": "0123456789",
"s_bank_name": "Santander",
"s_mandate": "MNDT-00042",
"s_type": "FAMILIAR",
"s_comment": "",
"s_comment2": "",
"b_paid": 0,
"b_rem_special": 0,
"b_retenido": 0,
"d_unreg_date": null,
"s_unreg_reason": "",
"people": [
{
"fk_i_member_id": 42,
"i_family": 1,
"s_first_name": "María",
"s_last_name": "García",
"s_dni": "12345678A",
"d_birth_date": "1985-03-15",
"s_phone": "612345678",
"s_email": "maria@example.com",
"b_lopd": 1,
"b_newsletter": 1,
"b_authorized": 1,
"b_authorized2": 0,
"s_photo_path": null
}
],
"cautions": [],
"comments": []
}
GET /members/quick — Búsqueda rápida por número
Query: fk_i_member_id=42 · i_family=1 (opcional)
Respuesta: objeto member completo
GET /members/first — Primer socio
GET /members/last — Último socio
GET /members/{id} — Socio por ID
GET /members/{id}/prev — Socio anterior
GET /members/{id}/next — Socio siguiente
Todas devuelven el objeto member completo.
GET /members/search — Autocompletar socios
Query: term=garcia
Respuesta 200
{
"0004201": "(00042-01) García, María",
"0004202": "(00042-02) García, Carlos"
}
POST /members/edit
Body: campos del objeto member a actualizar (pk_i_id requerido).
Respuesta 200
{ "msg": "Socio editado correctamente", "member": { "...": "objeto member completo" } }
POST /members/paid-caution — Toggle flag recibos pendientes
Body: pk_i_id
Respuesta: objeto member actualizado
POST /members/recover — Reactivar socio dado de baja
Body: pk_i_id
Respuesta: objeto member actualizado
POST /members/pre-delete — Pre-verificación antes de dar de baja
Body: pk_i_id
Respuesta 200
{ "pendientes": 0, "devueltos": 2, "revision": 0 }
POST /members/delete — Dar de baja a un socio
Body: pk_i_id · d_unreg_date · s_unreg_reason
Respuesta: objeto member actualizado
POST /members/change-type — Cambiar tipo de socio
Body: id · s_type
Respuesta 200: { "error": 0, "msg": "ok" }
POST /members/rem-special — Toggle remesa especial
Body: pk_i_id · b_rem_special
Respuesta: objeto member con campo error
POST /members/retener / POST /members/retener-cancel
Marca/desmarca al socio como retenido.
Body: member
Respuesta: { "msg": "...", "member": { ... } }
POST /members/promotion — Registrar promoción
Body: pk_i_id · friend
Respuesta: { "msg": "Promoción añadida correctamente", "member": { ... } }
POST /members/edit-comment — Editar comentario interno
Body: pk_i_id · s_comment2
Respuesta: { "msg": "...", "member": { ... } }
POST /members/comment/add — Añadir comentario
Body: member · comment
Respuesta: { "msg": "...", "member": { ... } }
GET /members/comment/edit — Obtener comentario para editar
Query: id
Respuesta: { "comment": { "id": 1, "comment": "texto", "created_at": "..." } }
POST /members/comment/edit-save — Guardar edición de comentario
Body: id · comment · pk_i_id
Respuesta: { "msg": "...", "member": { ... } }
POST /members/comment/delete — Eliminar comentario
Body: id ("old" para el comentario heredado) · member_id
Respuesta: { "msg": "Comentario borrado", "member": { ... } }
Familiares (people)
| Método | Ruta | Descripción |
|---|---|---|
POST |
/members/people/add |
Añadir familiar |
POST |
/members/people/edit |
Editar familiar |
POST |
/members/people/delete |
Eliminar familiar |
POST |
/members/people/auth |
Toggle autorización acceso |
POST |
/members/people/auth2 |
Toggle autorización 2 |
POST |
/members/people/picture/upload |
Subir foto (multipart webcam) |
POST |
/members/people/picture/delete |
Eliminar foto |
GET |
/members/people/card |
Tarjetas de acceso |
POST |
/members/people/card/add |
Añadir tarjeta |
POST |
/members/people/card/delete |
Eliminar tarjeta |
POST |
/members/people/password |
Generar enlace de reset de contraseña |
GET |
/members/people/card/preview |
Previsualizar carnet |
POST |
/members/people/card/print |
Imprimir carnet |
POST |
/members/people/minors-card |
Actualizar visibilidad carnets menores |
Todas las respuestas de escritura devuelven { "msg": "...", "member": { ... } } o { "error": 0, "msg": "..." }.
GET /members/people/card devuelve:
{
"cards": [
{ "pk_i_id": 1, "fk_i_member_id": 42, "i_family": 1, "s_card": "ABCD1234EFGH5678" }
]
}
POST /members/people/password devuelve:
{ "h": "https://app.example.com/password/reset/TOKEN?email=socio@example.com" }
9. Courses (cursos — admin)
GET /courses/levels 🔒
Query: course (código de actividad)
Respuesta 200
[
{ "i_code1": 1, "i_code2": 1, "i_code3": 0, "s_name": "Iniciación" },
{ "i_code1": 1, "i_code2": 2, "i_code3": 0, "s_name": "Avanzado" }
]
GET /courses/groups 🔒
Query: course · level
Respuesta 200
[
{
"i_code1": 1, "i_code2": 1, "i_code3": 1,
"s_name": "Lunes 18h-19h",
"f_price": "25.00",
"i_max_students": 15,
"s_hour": "L 18:00-19:00",
"s_monitor": "Carlos",
"s_place": "Pista 1",
"i_one_bill": 0,
"b_fitness": 0,
"b_pending_count": 0,
"s_comment": ""
}
]
GET /courses/group 🔒
Query: course · level · group
Respuesta: objeto grupo (igual que el array anterior, un único elemento)
GET /courses/data-alumni 🔒
Actividades en las que está inscrito un abonado.
Query: code (7 dígitos: {member}{family})
Respuesta 200
[
{ "i_activity": "0010101", "s_name": "Pádel Iniciación L18h" },
{ "i_activity": "0030101", "s_name": "Fitness Mañanas" }
]
GET /courses/alumnis 🔒
Lista de alumnos de un grupo.
Query: course · level · group · month (opcional) · year (opcional)
Respuesta 200
[
{
"pk_i_id": 1234,
"fk_i_member_id": "00042",
"fk_i_family": "01",
"i_activity": "0010101",
"s_last_name": "García",
"s_first_name": "María",
"d_reg_date": "01/09/2025",
"f_price": "25.00",
"mod_price": "25.00",
"ac_price": "25.00",
"s_type": "REMESA",
"s_comment": "",
"b_authorized": 1,
"b_authorized2": 0,
"i_door_log_count": 0
}
]
GET /courses/waitlist 🔒
Query: course · level · group
Respuesta: igual que /courses/alumnis con campo adicional dt_date.
GET /courses/alumni/get-reg-comment 🔒
Query: m · f · a
Respuesta 200
{
"fk_i_member_id": "00042",
"fk_i_family": "01",
"i_activity": "0010101",
"s_comment": "Interesada en el grupo de tarde si hay plaza."
}
GET /courses/alumni/get-unreg-comment 🔒
Query: i (ID del registro en unreg_requests)
Respuesta 200
{ "id": 5, "comment": "Se marcha al extranjero temporalmente." }
Escritura de cursos
| Método | Ruta | Body principal | Respuesta |
|---|---|---|---|
POST |
/courses/add |
s_name |
Nuevo i_code1 |
POST |
/courses/edit |
course · s_name |
"ok" |
POST |
/courses/delete |
course |
{ "error": 0, "msg": "..." } |
POST |
/courses/level/add |
course · s_name |
Nuevo i_code2 |
POST |
/courses/level/edit |
course · level · s_name |
"ok" |
POST |
/courses/level/delete |
course · level |
{ "error": 0, "msg": "..." } |
POST |
/courses/group/add |
course · level · s_name · f_price · i_max_students · s_hour · s_monitor · s_place |
"ok" |
POST |
/courses/group/edit |
id · s_field · s_value |
"ok" |
POST |
/courses/group/delete |
course · group |
{ "error": 0, "msg": "..." } |
POST |
/courses/group/comment |
course · level · group · comment |
{ "msg": "...", "error": 0 } |
POST |
/courses/alumni/add |
course · level · group · fk_i_member_id · d_date |
{ "error": 0, "msg": "..." } |
POST |
/courses/alumni/add-from-wait |
idem + email |
{ "error": 0, "msg": "..." } |
POST |
/courses/alumni/delete |
course · level · group · fk_i_member_id · fk_i_family |
{ "error": 0, "msg": "..." } |
POST |
/courses/alumni/delete-by-id |
id |
{ "error": 0, "msg": "..." } |
POST |
/courses/alumni/delete-by-ids |
ids (CSV) |
{ "error": 0, "msg": "..." } |
POST |
/courses/alumni/delete-wait |
course · level · group · fk_i_member_id · fk_i_family |
{ "error": 0, "msg": "..." } |
POST |
/courses/alumni/empty |
course · level · group |
{ "error": 0, "msg": "..." } |
POST |
/courses/alumni/import |
ocourse · olevel · ogroup · dcourse · dlevel · dgroup · date |
{ "error": 0, "msg": "..." } |
POST |
/courses/alumni/auth |
id · value |
{ "error": 0, "msg": "..." } |
POST |
/courses/alumni/auth2 |
id · value |
{ "error": 0, "msg": "..." } |
POST |
/courses/alumni/reg-comment |
m · f · a · s_comment |
{ "error": 0, "msg": "..." } |
POST |
/courses/alumni/unreg-comment |
id · s_comment |
{ "error": 0, "msg": "..." } |
10. Bills (recibos — admin)
GET /bills/member-search 🔒
Query: fk_i_member_id
Respuesta 200 — array de recibos:
[
{
"alumni": 1234,
"member": "00042",
"family": "01",
"name": "García, María",
"ac_name": "Pádel Iniciación L18h",
"activity": "0010101",
"price": "25.00",
"user_price": "25.00",
"bill_price": "25.00",
"month": 3,
"year": 2026,
"month_name": "marzo",
"status": 0,
"type": "REMESA",
"bonus": 0,
"cash_date": ""
}
]
Estado (
status):0pendiente ·1pagado ·2eliminado ·4devuelto.
GET /bills/alumni 🔒
Query: id (ID de alumno)
Respuesta 200
{
"pk_i_id": 1234,
"fk_i_member_id": "00042",
"fk_i_family": "01",
"i_activity": "0010101",
"f_price": "25.00",
"s_type": "REMESA",
"s_comment": "",
"person": { "s_first_name": "María", "s_last_name": "García" },
"next_bills": [
{ "i_month": 4, "i_year": 2026, "i_status": 0, "f_price": "25.00" },
{ "i_month": 5, "i_year": 2026, "i_status": 0, "f_price": "25.00" }
]
}
GET /bills/from-alumni 🔒
Query: id
Respuesta 200
{
"pk_i_id": 1234,
"i_activity": "0010101",
"person": { "s_first_name": "María", "s_last_name": "García" },
"bills": [
{ "i_month": 1, "i_year": 2026, "i_status": 1, "f_price": "25.00", "year": 0 },
{ "i_month": 2, "i_year": 2026, "i_status": 1, "f_price": "25.00", "year": 0 },
{ "i_month": 3, "i_year": 2026, "i_status": 0, "f_price": "25.00", "year": 0 }
]
}
GET /bills/number 🔒
Query: course · level · group · month · year · type (BANK/ALL) · alumni[] (opcional)
Respuesta 200
12
GET /bills/pending 🔒
Query: id (member) · complete (0/1)
Respuesta 200 — array de recibos pendientes (misma estructura que /bills/member-search)
GET /bills/search 🔒
Query: fk_i_member_id · i_month · status · ext
Respuesta 200
{
"iTotalRecords": 5,
"iTotalDisplayRecords": 5,
"aaData": [ { "...": "objeto recibo" } ]
}
GET /bills/remittance-return/member 🔒
Query: member
Respuesta 200 — mapa de miembros con recibos devueltos:
{
"42": {
"pk_i_id": 42,
"people": [ { "...": "..." } ],
"months": { "3": 1 },
"bills": [ { "...": "..." } ],
"i_total": "25.00"
}
}
Escritura de recibos
| Método | Ruta | Body | Respuesta |
|---|---|---|---|
POST |
/bills/alumni/edit |
id · price · type · comment |
{ "error": 0, "msg": "..." } |
POST |
/bills/generate |
id · month · year |
{ "error": 0, "msg": "Recibo creado" } |
POST |
/bills/generate-next |
course · level · group · month · year |
{ "msg": "Recibos generados", "error": 0 } |
POST |
/bills/generate-multi |
activity · id · months[] |
{ "iTotalRecords": N, "aaData": [...] } |
POST |
/bills/generate-remittance |
course · level · group · month · year |
{ "error": 0, "msg": "...", "paid_bills": 12 } |
POST |
/bills/ticket |
bills[] |
{ "error": 0, "msg": "...", "ticket_number": "2025/000123", "lines": [] } |
POST |
/bills/cancel |
acs[] |
{ "error": 0, "msg": "OK", "lines": [] } |
POST |
/bills/delete |
acs[] |
{ "error": 0, "msg": "OK" } |
POST |
/bills/delete-alumni |
ids (CSV) · month · year |
{ "error": 0, "msg": "OK" } |
POST |
/bills/recover |
acs[] |
{ "error": 0, "msg": "OK" } |
POST |
/bills/remittance-return/add |
member · month · year |
{ "error": 0, "msg": "OK" } |
POST |
/bills/remittance-return/delete |
alumni · month · year · id · special |
{ "error": 0, "msg": "..." } |
POST |
/bills/remittance-return/print |
id |
{ "msg": "...", "data": { "id": 1 }, "lines": [] } |
11. Booking Admin (reservas — admin)
GET /booking-admin/grid 🔒
Query: fk_i_activity_id · d_date (dd/mm/yyyy)
Respuesta 200
{
"aaData": [
["<div id=\"0\">0900-1000</div>", "00042.1+", "", "00123.2", ""],
["<div id=\"1\">1000-1100</div>", "", "", "", "00456.1"]
],
"aoColumns": [
{ "sTitle": "Horarios", "sClass": "celda_horario", "sWidth": "65px" },
{ "sTitle": "01", "sClass": "celda_normal", "sWidth": "95px" },
{ "sTitle": "02", "sClass": "celda_normal", "sWidth": "95px" }
],
"ac": { "pk_i_activity_id": 1, "s_name": "PÁDEL MURO", "i_courts": 4 },
"light": 100,
"extra": 150,
"extra2": 150
}
En
aaData, la celda contiene{member}.{family}[+]si está ocupada,""si libre. El+indica pagado.
GET /booking-admin/shared 🔒
Query: fk_i_activity_id · d_date · hour · court
Respuesta 200 — array de reservas en la misma hora/pista (compartidas)
GET /booking-admin/single 🔒
Query: fk_i_activity_id · d_date · hour · aPos[1]
Respuesta 200
{ "fk_i_member_id": 42, "fk_i_family": 1, "d_date": "2026-03-18", "b_paid": 0 }
GET /booking-admin/single-by-id 🔒
Query: id
Respuesta 200
{ "pk_i_id": 1234, "fk_i_member_id": 42, "fk_i_family": 1, "d_date": "2026-03-18", "b_paid": 0 }
POST /booking-admin/do 🔒
Body: fk_i_activity_id · hour · d_date · court · member · aPos[]
Respuesta 200
{
"msg": "Pista reservada correctamente",
"error": 1,
"cell": "2x1",
"book": { "fk_i_member_id": 42 }
}
error:0fallo ·1OK ·2ya pagada ·3ocupada por otro ·4recibos pendientes ·5dado de baja.
POST /booking-admin/confirm 🔒
Body: id (ID de reserva pendiente de confirmar)
Respuesta 200 — misma estructura que /booking-admin/do
POST /booking-admin/empty 🔒
Body: fk_i_activity_id · hour · s_hour · d_date · aPos[]
Respuesta 200
{ "error": 2, "book": { "pk_i_id": 1234, "b_paid": 0, "text": "" } }
error:0nada que vaciar ·1estaba pagada (devolver ticket) ·2eliminada (no pagada) ·3eliminada (pagada sin ticket).
POST /booking-admin/empty-by-id 🔒
Body: id
Respuesta: igual que /booking-admin/empty
12. Cash (caja — admin)
GET /cash/last-ticket 🔒
Query: iPage (paginación, base 0)
Respuesta 200
{
"ticket": [
{ "dt_date": "2026-03-18 10:23:45", "i_line": 1, "s_line": "--------------------------------" },
{ "dt_date": "2026-03-18 10:23:45", "i_line": 2, "s_line": "CLUB DEPORTIVO SANTA ANA" },
{ "dt_date": "2026-03-18 10:23:45", "i_line": 3, "s_line": "Reserva pádel 6,00 €" }
]
}
GET /cash/search 🔒
Query: searchQuery · paymentType · iPage
Respuesta 200
{
"items": [
{
"pk_i_id": 12345,
"pk_s_id": "2026/000042",
"d_year": 2026,
"dt_date": "2026-03-18 10:23:45",
"fk_s_activity_group_id":"AC",
"fk_i_activity_id": "01",
"fk_i_member_id": "00042",
"s_name": "García, María",
"s_concept": "Reserva pádel",
"f_price": 6000000,
"f_tax": 0,
"f_amount": "6.00",
"s_type": "CAJA"
}
]
}
GET /cash/ticket-from-booking 🔒
Query: ac · hour · court · date
Respuesta 200
{ "error": 0, "ticket": [ { "...": "objeto cash" } ] }
Escritura de caja
| Método | Ruta | Body | Respuesta |
|---|---|---|---|
POST |
/cash/post |
fk_i_member_id · items[] · prices[] · concepts[] · taxes[] · amounts[] · payment_type · dt_date |
{ "msg": "...", "total": 6000000, "pk_s_id": "2026/000042", "data": "" } |
POST |
/cash/post-ticket |
datos del ticket | { "msg": "...", "data": "", "lines": [] } |
POST |
/cash/print-ticket |
date |
{ "lines": ["linea1", "linea2"] } |
POST |
/cash/delete |
id |
{ "error": 0, "msg": "..." } |
POST |
/cash/delete-mov |
sdate · edate |
{ "error": 0, "msg": "OK" } |
POST |
/cash/book-ticket |
datos reserva + pago | { "msg": "...", "data": "", "lines": [] } |
POST |
/cash/book-return |
datos devolución | { "error": 0, "book": {}, "lines": [] } |
POST |
/cash/bonus-ticket |
datos bono | { "error": 0, "lines": [] } |
POST |
/cash/bonus-ticket-nopaid |
datos bono | { "error": 0, "lines": [] } |
POST |
/cash/qr |
member · familiar |
{ "msg": "ok", "error": 0, "qr": "00042-01-ABCDEF123456" } |
13. Dayoff / Celebrations
| Método | Ruta | Body | Respuesta |
|---|---|---|---|
POST |
/dayoff/add |
d_date (dd/mm/yyyy) · s_name · type |
1 |
POST |
/dayoff/delete |
d_date · s_name |
1 |
POST |
/celebration/add |
date (dd/mm/yyyy) · name · member · comment |
1 |
POST |
/celebration/delete |
id |
1 |
14. Remittance (remesas especiales)
POST /remittance/member/add 🔒
Body: id (remittance ID) · member · amount · concept
Respuesta 200
{ "error": 0, "msg": "Socio añadido correctamente" }
POST /remittance/member/delete 🔒
Body: id
Respuesta 200
{ "error": 0, "msg": "Socio eliminado correctamente" }
POST /remittance/edit 🔒
Body: id · field · value
Respuesta 200
{ "error": 0, "msg": "Editado correctamente" }
POST /remittance/sepa 🔒
Body: id (remittance ID)
Respuesta 200
{
"error": 0,
"msg": "Remesa generada correctamente",
"file": "/storage/remesas/2026_sepa.xml",
"count": 42
}
15. Inscriptions (preinscripciones)
El objeto inscription tiene esta estructura:
{
"id": 1,
"address": "Calle Mayor 12",
"city": "Madrid",
"zip_code": "28001",
"emergency_phone": "612345678",
"bank": "0049",
"bank_office": "1500",
"bank_sec_code": "42",
"bank_account": "0123456789",
"comment": "",
"know_us": "amigo",
"know_us_comment": "",
"know_us_by_who": "",
"created_at": "2026-03-01T10:00:00.000Z",
"people": [
{
"first_name": "Luis",
"last_name": "Pérez",
"email": "luis@example.com",
"phone": "634567890",
"birth_date": "15/04/1990",
"dni": "87654321B"
}
]
}
| Método | Ruta | Descripción | Respuesta |
|---|---|---|---|
GET |
/inscriptions/first |
Primera preinscripción | objeto inscription |
GET |
/inscriptions/last |
Última preinscripción | objeto inscription |
GET |
/inscriptions/{id} |
Preinscripción por ID | objeto inscription |
GET |
/inscriptions/{id}/prev |
Anterior | objeto inscription |
GET |
/inscriptions/{id}/next |
Siguiente | objeto inscription |
POST |
/inscriptions |
Convertir en socio | { "error": 0, "msg": "Usuario creado correctamente", "id": 1234 } |
DELETE |
/inscriptions/{id} |
Eliminar preinscripción | objeto inscription siguiente |
POST /inscriptions — Body
| Campo | Tipo |
|---|---|
| inscription_id | integer |
| s_type | string (INDIVIDUAL / FAMILIAR / SABIC / ...) |
| id | integer |
| d_reg_date | string |
16. Admin Misc
POST /admin/quota 🔒
Actualiza el precio/cupo de una actividad.
Body: pk_s_group_id · pk_i_activity_id · s_field · s_value
Respuesta 200
1
POST /admin/reboot 🔒
Reinicia la impresora.
Respuesta 200
{ "error": 0, "msg": "Reiniciando impresora..." }
GET /admin/check-reboot 🔒
Respuesta 200
{ "status": "ok" }
GET /admin/bank-sec-code 🔒
Calcula el dígito de control bancario.
Query: bank · office · account
Respuesta 200
"42"
GET /admin/bank-name 🔒
Query: bank (código 4 dígitos)
Respuesta 200
{ "name": "Banco Santander" }
POST /admin/print-card 🔒
Body: member · family
Respuesta 200
{ "error": 0, "msg": "Carnet enviado a imprimir" }
POST /admin/set-printer 🔒
Body: printer (nombre/IP)
Respuesta 200
{ "error": 0, "msg": "Impresora configurada correctamente" }
POST /admin/sorteo 🔒
Registra participaciones en sorteo.
Body: data[] (array de { member, name, email, phone, tickets })
Respuesta 200
{ "error": 0, "msg": "Participación registrada" }
17. Printer
GET /printer/lines 🔒
Devuelve líneas pendientes de imprimir.
Respuesta 200
{ "error": 0, "lines": [] }
18. Hash (público)
GET /hash/{hash}
Devuelve el hash BCrypt de un valor, en base64. Útil para generar contraseñas desde scripts.
Ejemplo: GET /2.0/hash/mipassword
Respuesta 200
{ "h": "JDJ5JDEwJGFCQ0Rm..." }
Códigos de error comunes
Campo error |
Significado |
|---|---|
"0" / 0 |
Operación correcta |
"1" / 1 |
Error genérico o entidad no encontrada |
"2" |
Ya existe / ya está pagado |
"3" |
Ocupado por otro usuario |
"4" |
Recibos pendientes — acceso restringido |
"5" |
Dado de baja — acceso restringido |
Convenciones
- Montos se almacenan internamente en millonésimas de euro (
6000000=6.00 €). La API devuelve el valor formateado como string ("6.00") en los recursos de la app. - Fechas en pantalla usan formato
dd/mm/yyyy; en base de datosyyyy-mm-dd. - Códigos de actividad son cadenas de 7 dígitos:
{course:3}{level:2}{group:2}→0010102. - Identificador de abonado combina miembro y familiar:
{member:5}{family:2}→0004201.