API
Todo lo que la aplicación hace con una villa, una reserva o un cliente es accesible por HTTP. Un script — o un agente — trabaja con los mismos datos que la interfaz, bajo las mismas reglas, sin sesión de navegador.
Esta página es el mapa: la autenticación, la forma de cada respuesta, y cada endpoint con la página que lo detalla. Cada endpoint tiene su propia página: una llamada, sus parámetros, sus respuestas y lo que rechaza.
Autenticación
Cada petición a /api/v1 lleva una clave API en la cabecera x-api-key. Una clave se crea desde
Cuenta → Claves API y pertenece a una sola organización: esa organización es todo el alcance
de la clave.
curl -H "x-api-key: $VILLASLOT_API_KEY" \
"https://villaslot.app/api/v1/me"La organización nunca va en la petición
Ni en el cuerpo, ni en la URL, ni en una cabecera. Viene de la clave y de nada más. Un
recurso que pertenece a otra organización responde 404, exactamente igual que un identificador que no existe.
La clave actúa como la persona que la creó
Una clave no es una segunda identidad con sus propios poderes. Lleva los derechos del miembro que la creó, en la organización para la que se creó. Nada es posible por la API que esa misma persona no pudiera hacer en la interfaz — y no se rechaza nada que sí pudiera hacer.
Una clave deja de funcionar cuando su portador deja la organización. Ningún acceso
huérfano sobrevive a una salida: la clave responde 401 a partir de ese momento, exactamente
como si se hubiera revocado. Revocar la clave de alguien que se ha ido es, por tanto,
limpieza, no una corrección de seguridad.
Dos preguntas deciden cada llamada, y las dos tienen que superarse:
| Pregunta | La decide | Respuesta si falla |
|---|---|---|
| ¿El portador sigue siendo miembro, y con qué rol? | El portador de la clave y su rol | 401 / 403 |
| ¿El recurso pertenece a la organización de la clave? | La organización de la clave | 404 |
Quién puede hacer qué
| Operación | Rol mínimo en la organización |
|---|---|
| Leer cualquier cosa | member |
| Crear y corregir clientes, crear y gestionar reservas | member |
| Crear, renombrar, archivar una villa, su foto, su horario, sus tarifas | admin |
| Cambiar las reglas de reserva de la organización | admin |
Ese reparto no es una decisión de la API: es la propia matriz de permisos del producto. Un miembro suele ser quien tiene al cliente al teléfono, y el producto reserva la configuración de las villas al propietario y a los administradores de la organización.
Sobre de respuesta
| Caso | Cuerpo |
|---|---|
| Éxito | {"success": true, "data": …} |
| Lista paginada | {"success": true, "data": [...], "pagination": {"total", "page", "limit", "totalPages"}} |
| Error | {"error": "…"} |
| Error de validación | {"error": "…", "details": [ … field-level issues … ]} |
| Rechazo de negocio | {"error": "…", "detail": { … reason, names, amounts … }} |
| Estado | Cuándo |
|---|---|
200 | Lectura o cambio realizado |
201 | Recurso creado |
401 | Clave ausente o no válida, o clave cuyo portador ha dejado la organización |
403 | El portador es un miembro legítimo, pero su rol es demasiado bajo |
404 | Recurso desconocido, o recurso de otra organización |
409 | Conflicto de estado — una franja ocupada, un estado que ha cambiado, un límite del plan alcanzado |
413 | Un lote por encima de su límite; el mensaje indica el límite |
422 | Parámetros o cuerpo no válidos — details enumera los campos afectados |
429 | Límite de peticiones de la clave superado (120 peticiones por minuto) |
500 | Error inesperado del servidor |
Un recurso de otra organización responde 404, nunca 403. Un 403
confirmaría que el identificador existe. La misma respuesta para un identificador desconocido y para
uno que no tienes permiso para leer — no puedes distinguirlos, y esa es
la idea. El 403 está reservado a la otra pregunta: estás en la organización correcta,
pero tu rol es demasiado bajo.
Unidades y convenciones
- Los importes son enteros en la unidad menor de la moneda de la organización.
1500000enIDRson 15 000 rupias;4500enEURson 45,00 €. Nunca dividas entre 100 sin conocer la moneda. - Los instantes están en ISO 8601 y en UTC (
startAt,endAt,createdAt). - Los días y las horas son locales de la organización: una reserva se crea con
date(YYYY-MM-DD) ystartMinute(minutos desde la medianoche local). Leesettings.timezoneenGET /api/v1/me. - El horario de apertura son minutos locales semanales, con
dayOfWeekde0domingo …6sábado.
Cada endpoint
| Método | Ruta | Qué hace | Rol |
|---|---|---|---|
GET | /api/v1/me | Mi contexto | member |
GET | /api/v1/properties | Listar las villas | member |
POST | /api/v1/properties | Crear una villa | admin |
GET | /api/v1/properties/{propertyId} | Leer una villa | member |
PATCH | /api/v1/properties/{propertyId} | Renombrar una villa | admin |
POST | /api/v1/properties/{propertyId}/archive | Archivar una villa | admin |
POST | /api/v1/properties/{propertyId}/photo | Subir una foto | admin |
GET | /api/v1/properties/{propertyId}/opening-hours | Leer el horario de apertura | member |
PUT | /api/v1/properties/{propertyId}/opening-hours | Reemplazar el horario de apertura | admin |
GET | /api/v1/properties/{propertyId}/rates | Leer la cuadrícula de tarifas | member |
PUT | /api/v1/properties/{propertyId}/rates | Reemplazar la cuadrícula de tarifas | admin |
GET | /api/v1/properties/{propertyId}/availability | Leer la disponibilidad | member |
GET | /api/v1/bookings | Listar las reservas | member |
POST | /api/v1/bookings | Crear una reserva | member |
GET | /api/v1/bookings/{bookingId} | Leer una reserva | member |
POST | /api/v1/bookings/{bookingId}/confirm | Confirmar una reserva | member |
POST | /api/v1/bookings/{bookingId}/complete | Completar una reserva | member |
POST | /api/v1/bookings/{bookingId}/cancel | Cancelar una reserva | member |
POST | /api/v1/bookings/{bookingId}/reschedule | Reprogramar una reserva | member |
GET | /api/v1/customers | Listar los clientes | member |
POST | /api/v1/customers | Crear un cliente | member |
POST | /api/v1/customers/bulk | Importar clientes | member |
GET | /api/v1/customers/{customerId} | Leer un cliente | member |
PATCH | /api/v1/customers/{customerId} | Modificar un cliente | member |
GET | /api/v1/settings/booking | Leer las reglas de reserva | member |
PATCH | /api/v1/settings/booking | Modificar las reglas de reserva | admin |
Límite de peticiones
El límite lo lleva la clave, no la IP: 120 peticiones por minuto. Una clave por encima de su límite
responde 429 en todos los endpoints. Espera y vuelve a intentarlo — no se ha hecho nada.
Por dónde empezar
Llama primero a GET /api/v1/me: convierte una simple clave en un
contexto — la organización que abre, el rol que lleva, la zona horaria y la moneda de las que dependen todas las demás
llamadas, y cuánto espacio deja el plan.
Después, el camino habitual: buscar o crear el cliente, pedir la disponibilidad de una villa, y crear la reserva. Toda la secuencia, con sus rechazos, se recorre en Crear una reserva.