Visión general
La API REST v1 de SES.Hospedajes permite a sistemas externos (PMS, ERPs, sistemas propios de rent-a-car) registrar huéspedes y contratos de alquiler de vehículo en la plataforma. Los registros creados a través de la API se procesan exactamente igual que los introducidos desde la interfaz web, incluyendo el envío automático a la sede electrónica del Ministerio del Interior (SES.Hospedajes / VUD).
La API utiliza HTTPS, JSON para request y response, autenticación por API Key en
cabecera HTTP y convenciones REST estándar (verbos GET/POST/PUT/DELETE,
códigos HTTP semánticos).
Casos de uso cubiertos
- Hospedaje — alta de huéspedes (parte de viajero) por establecimiento.
- Rent-a-Car — alta de contrato de alquiler con vehículo, titular, conductores, permisos de conducir y direcciones de recogida y devolución.
- Consulta — listados, filtros y obtención de detalle de cualquier recurso creado.
- Edición — actualización y eliminación de registros propios.
Primeros pasos
- El propietario de la cuenta debe disponer de plan Premium con la API habilitada.
- Desde el panel de la cuenta puede generarse una API Key de producción y, opcionalmente, una API Key de sandbox para pruebas (ver Entorno de pruebas).
- Toda llamada incluye la cabecera
X-Api-Key: <tu_api_key>. - La base URL es
https://seshospedajes.es/app/api/v1. - Para validar la integración, llamar primero a
GET /v1/ping.
Primera llamada
curl -sS https://seshospedajes.es/app/api/v1/ping \
-H 'X-Api-Key: TU_API_KEY'
Respuesta esperada:
{
"ok": true,
"ts": "2026-06-25T12:00:00+00:00",
"userId": 123,
"sandbox": false,
"env": "production"
}
Autenticación
Toda petición a la API debe incluir una API Key válida. Se acepta en tres formas, por orden de prioridad:
- Cabecera
X-Api-Key: <clave>recomendado - Cabecera
Api-Key: <clave> - Parámetro de query
?api_key=<clave>— solo para pruebas; no usar en producción
Ejemplos en distintos lenguajes
curl -sS https://seshospedajes.es/app/api/v1/establishments \
-H 'X-Api-Key: TU_API_KEY'Códigos de error de autenticación
| HTTP | code | Descripción |
|---|---|---|
| 401 | auth_missing | No se proporcionó API Key. |
| 401 | auth_invalid | La API Key no existe. |
| 401 | auth_inactive | La API Key existe pero está desactivada. |
| 403 | plan_required | El plan de la cuenta no incluye acceso a la API. |
| 403 | api_disabled | La API está desactivada para la cuenta. |
Entorno de pruebas
La plataforma ofrece un modo sandbox a través de API Keys marcadas como tal. Una API Key de sandbox permite ejercitar todos los endpoints exactamente igual que en producción (mismos campos, mismas validaciones, mismos códigos de respuesta), con una única diferencia operativa:
enviado_ministerio = 2 y nunca se envían al Ministerio del
Interior. El resto de la persistencia es real: los registros se crean
en las mismas tablas y son visibles en el panel de la cuenta.
Cómo identificar una key de sandbox
La respuesta de GET /v1/ping incluye los campos sandbox
(booleano) y env ("production" o "sandbox").
Es la forma fiable de saber contra qué entorno está ejecutando la integración.
// Respuesta con API Key de sandbox
{
"ok": true,
"ts": "2026-06-25T12:00:00+00:00",
"userId": 123,
"sandbox": true,
"env": "sandbox"
}
Buenas prácticas de pruebas
- Realizar la integración completa contra sandbox antes de cambiar a la API Key de producción.
- Probar tanto el camino feliz (alta atómica) como los caminos de error (campos faltantes, formatos inválidos, reenvío idempotente).
- Confirmar que la integración lee correctamente
envenpingy muestra al operador en qué entorno está trabajando. - Los registros sandbox pueden eliminarse con
DELETE /v1/contracts/{id}sin afectar a producción.
URLs base y versionado
La API mantiene una única versión pública estable, identificada en la ruta:
https://seshospedajes.es/app/api/v1/{recurso}
La numeración semántica de la API se publica en la respuesta de
GET /v1/ping mediante la cabecera de versión del OpenAPI
(openapi.yaml). Los cambios incompatibles
siempre implican una nueva versión mayor (/v2); las versiones
en uso se mantienen al menos 12 meses tras la publicación de la siguiente.
Paginación y filtros
Todos los listados (GET sobre una colección) aceptan los siguientes parámetros de query:
| Parámetro | Tipo | Por defecto | Descripción |
|---|---|---|---|
page | integer | 1 | Número de página, empezando por 1. |
limit | integer | 20 | Tamaño de página. Máximo 200. |
q | string | — | Búsqueda textual. Campos cubiertos detallados en cada endpoint. |
from | date (YYYY-MM-DD) | — | Filtro de fecha mínima. Campo de fecha aplicado: ver cada endpoint. |
to | date (YYYY-MM-DD) | — | Filtro de fecha máxima. Inclusivo. |
contract_id | integer | — | Solo aplicable a /v1/vehicles y /v1/persons. Filtra por contrato. |
Forma de la respuesta paginada
{
"ok": true,
"data": [ /* registros */ ],
"page": 1,
"limit": 20,
"total": 137
}
Idempotencia
Para evitar duplicados en caso de reintentos por timeout o errores de red, todos
los endpoints POST aceptan un campo uuid opcional en el
cuerpo. Si una llamada posterior llega con el mismo uuid bajo la
misma cuenta, la respuesta es 200 OK con
"idempotent": true y los datos del registro existente, sin crear
duplicados.
Adicionalmente, algunos endpoints usan claves naturales como respaldo:
| Endpoint | Clave natural de idempotencia |
|---|---|
POST /v1/contracts | referencia + cuenta del propietario. |
POST /v1/guests | numero_documento + fecha_entrada + establecimiento_id. |
POST /v1/rentacar/contracts | uuid del envoltorio o referencia del contrato. |
Si una llamada se considera idempotente, la respuesta incluye idempotent: true
y los identificadores del registro previo. Es seguro reintentar cualquier
POST tras un error transitorio.
Fechas, horas y zonas horarias
- Fechas en formato ISO 8601
YYYY-MM-DD(ejemplo:2026-07-15). - Horas en formato
HH:MM:SSen 24h (ejemplo:15:00:00). - Datetime compuesto
YYYY-MM-DD HH:MM:SS(ejemplo:2026-07-15 15:00:00). - Zona horaria: todas las fechas y horas se interpretan en
Europe/Madrid. Las fechas se devuelven en el mismo formato. - Códigos de país en ISO 3166-1 alpha-3 (ejemplo:
ESP,FRA,GBR). - Códigos de municipio según el padrón del INE (5 dígitos, ejemplo:
28079para Madrid).
Códigos de error
Todas las respuestas de error siguen el mismo formato JSON:
{
"ok": false,
"code": "validation_error",
"message": "Datos con formato inválido",
"fields": {
"fecha_entrada": "Formato esperado YYYY-MM-DD",
"contacto_email": "Email inválido"
}
}
| HTTP | code | Descripción |
|---|---|---|
| 400 | bad_json | El cuerpo de la petición no es JSON válido. |
| 400 | no_changes | El cuerpo de un PUT/PATCH no contiene campos modificables. |
| 401 | auth_missing | Falta cabecera de autenticación. |
| 401 | auth_invalid | API Key no encontrada. |
| 401 | auth_inactive | API Key desactivada. |
| 403 | plan_required | El plan de la cuenta no permite usar la API. |
| 403 | api_disabled | La API no está habilitada para la cuenta. |
| 403 | forbidden | El recurso solicitado no pertenece a la cuenta autenticada. |
| 404 | not_found | El recurso o la ruta no existen. |
| 405 | method_not_allowed | Verbo HTTP no permitido en la ruta. |
| 422 | missing_fields | Faltan campos obligatorios. Detalle en fields (array). |
| 422 | validation_error | Algún campo tiene un formato inválido. Detalle en fields (objeto). |
| 500 | server_error | Error inesperado. Las altas atómicas garantizan que no queden registros parciales. |
| 500 | db_connect | Indisponibilidad temporal de la base de datos. |
Límites de uso
No se aplican límites estrictos por defecto. Para integraciones de alta frecuencia (carga inicial, sincronización masiva), se recomienda:
- Limitar la concurrencia a 5 peticiones simultáneas por API Key.
- Implementar reintentos con exponential backoff ante respuestas
5xx, comenzando en 1 segundo y duplicando hasta un máximo de 60 segundos. - Reutilizar
uuiden los reintentos para garantizar idempotencia. - Para cargas iniciales de más de 10.000 registros, espaciar las cargas en lotes con pausa entre lotes.
Health check
Comprueba conectividad, autenticación y entorno (producción o sandbox).
Respuesta
{
"ok": true,
"ts": "2026-06-25T12:00:00+00:00",
"userId": 123,
"sandbox": false,
"env": "production"
}
Establecimientos
Un establecimiento representa una unidad operativa (hotel, oficina de rent-a-car, agencia, etc.) registrada ante el Ministerio del Interior. Toda alta de huésped o contrato debe asociarse a un establecimiento de la cuenta autenticada.
Listado de establecimientos de la cuenta. Filtros: q sobre nombre y numero_establecimiento.
Cuerpo
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| nombre | string | sí | Nombre del establecimiento. |
| numero_establecimiento | string | sí | Código asignado por el Ministerio del Interior. |
| uuid | string (uuid) | opcional | Para idempotencia. |
Ejemplo
{
"nombre": "Oficina Aeropuerto T1",
"numero_establecimiento": "R12345"
}
Detalle, actualización parcial y eliminación. Solo accesibles a establecimientos de la cuenta autenticada.
Huéspedes (hospedaje)
Recurso aplicable únicamente a hospedaje. Para rent-a-car, las personas
(titulares y conductores) se gestionan a través de
/v1/persons.
Filtros: q sobre nombre, apellido1, apellido2, numero_documento, contacto_email. from/to sobre fecha_entrada.
Cuerpo
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| nombre | string | sí | |
| apellido1 | string | sí | |
| apellido2 | string | opcional | |
| establecimiento_id | integer | sí | Debe pertenecer a la cuenta. |
| tipo_documento | enum | opcional | DNI, NIE o PASAPORTE. |
| numero_documento | string | opcional | |
| fecha_nacimiento | date | opcional | YYYY-MM-DD. |
| nacionalidad | string (3) | opcional | ISO 3166-1 alpha-3. |
| genero | enum | opcional | M, F u Otro. |
| contacto_email | opcional | ||
| contacto_telefono | string | opcional | |
| fecha_entrada | date | opcional | YYYY-MM-DD. |
| hora_entrada | time | opcional | HH:MM:SS. |
| fecha_salida | date | opcional | |
| hora_salida | time | opcional | |
| habitacion | string | opcional | |
| uuid | string (uuid) | opcional | Idempotencia. |
Detalle, actualización parcial y eliminación.
Contratos (cabecera)
Endpoints de bajo nivel sobre la tabla común de contratos. Cubre la cabecera
de cualquier alquiler. Para rent-a-car se recomienda usar el endpoint atómico
POST /v1/rentacar/contracts, que crea
contrato, vehículo, personas, permisos y direcciones en una sola transacción.
Filtros: q sobre referencia y numero_establecimiento. from/to sobre fecha_contrato.
Cuerpo
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| establecimiento_id | integer | sí | |
| referencia | string | sí | Identificador del contrato. Único por cuenta. |
| fecha_contrato | date | opcional | |
| fecha_recogida | datetime | opcional | |
| fecha_devolucion | datetime | opcional | |
| tipo_pago | string | opcional | Por ejemplo TARJETA, EFECTIVO. |
| fecha_pago | date | opcional | |
| medio_pago | string | opcional | |
| titular_pago | string | opcional | |
| caducidad_tarjeta | string | opcional | Formato MM/AA. |
| codigo_establecimiento_mir | string | opcional | Si difiere del registrado en el establecimiento. |
| uuid | string (uuid) | opcional | Idempotencia. |
Precheckins (solo lectura)
Listado de enlaces de precheckin generados. Filtros: q sobre nombre_hotel, email_cliente, uuid. from/to sobre fecha_envio.
Rent-a-Car — Modelo de datos
El alta de un contrato de alquiler de vehículo se compone de los siguientes recursos:
| Recurso | Cardinalidad por contrato | Descripción |
|---|---|---|
Contrato (contract) | 1 | Cabecera: referencia, fechas, datos de pago. |
Vehículo (vehicle) | 1 | Vehículo asignado al contrato. |
Persona (person) | 1 a 3 | Titular (rol TI), conductor principal (CP) y conductor secundario opcional (CS). |
Permiso de conducir (license) | 0 o 1 por persona | Datos del carnet del conductor. |
Dirección de persona (address tipo persona) | 0 o 1 por persona | Domicilio personal del conductor. |
Dirección de recogida (pickup_address) | 0 o 1 | Localización donde se retira el vehículo. |
Dirección de devolución (dropoff_address) | 0 o 1 | Localización donde se entrega el vehículo. |
Roles de persona
| Código | Rol |
|---|---|
TI | Titular del contrato |
CP | Conductor principal |
CS | Conductor secundario |
Cada rol puede aparecer como máximo una vez por contrato.
Alta de contrato rent-a-car (transacción única)
Crea en una sola transacción: contrato, vehículo, hasta tres personas con su permiso de conducir y dirección personal, y direcciones de recogida y devolución. Si cualquier paso falla, no se persiste ningún registro.
Este es el endpoint recomendado para integraciones rent-a-car. Para correcciones puntuales posteriores, los CRUDs específicos (vehículos, personas, permisos, direcciones) están disponibles.
Estructura del cuerpo
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| uuid | string (uuid) | opcional | Idempotencia del envoltorio. |
| contract | object | sí | Cabecera del contrato. Ver tabla en /v1/contracts. |
| vehicle | object | sí | Datos del vehículo. Ver /v1/vehicles. |
| persons | array (1–3) | sí | Cada elemento es una persona; admite license y address anidados. |
| pickup_address | object | opcional | Dirección de recogida del vehículo. |
| dropoff_address | object | opcional | Dirección de devolución del vehículo. |
Ejemplo de petición
POST /v1/rentacar/contracts
Content-Type: application/json
X-Api-Key: TU_API_KEY
{
"uuid": "8d2e1c0a-7b21-4f0a-9a91-8b22d3f3a001",
"contract": {
"establecimiento_id": 12,
"referencia": "RC-2026-0007",
"fecha_contrato": "2026-06-25",
"fecha_recogida": "2026-06-26 10:00:00",
"fecha_devolucion": "2026-06-30 18:00:00",
"tipo_pago": "TARJETA",
"fecha_pago": "2026-06-25",
"medio_pago": "VISA",
"titular_pago": "Ana García",
"caducidad_tarjeta": "12/28"
},
"vehicle": {
"categoria": "TURISMO_M1",
"tipo": "TURISMO",
"marca": "SEAT",
"modelo": "Ibiza",
"matricula": "1234ABC",
"numero_bastidor": "VSSZZZ6JZNR123456",
"color": "BLANCO",
"km_recogida": 12030
},
"pickup_address": {
"direccion": "Aeropuerto T1, Mostrador 4",
"codigo_municipio": "28079",
"nombre_municipio": "Madrid",
"codigo_postal": "28042",
"pais": "ESP"
},
"dropoff_address": {
"direccion": "Aeropuerto T4, Devolución",
"codigo_municipio": "28079",
"nombre_municipio": "Madrid",
"codigo_postal": "28042",
"pais": "ESP"
},
"persons": [
{
"rol": "TI",
"nombre": "Ana", "apellido1": "García", "apellido2": "López",
"tipo_documento": "NIF", "numero_documento": "12345678Z",
"fecha_nacimiento": "1985-03-12", "nacionalidad": "ESP", "sexo": "M",
"telefono": "+34600111222", "correo": "ana@example.com",
"license": { "tipo": "B", "validez": "2030-01-01", "numero": "B12345678" },
"address": {
"direccion": "Calle Mayor 1",
"codigo_municipio": "28079", "nombre_municipio": "Madrid",
"codigo_postal": "28013", "pais": "ESP"
}
},
{
"rol": "CP",
"nombre": "Luis", "apellido1": "Pérez",
"tipo_documento": "NIF", "numero_documento": "87654321X",
"fecha_nacimiento": "1990-07-08", "nacionalidad": "ESP", "sexo": "H",
"license": { "tipo": "B", "validez": "2031-06-01", "numero": "L7654321" },
"address": {
"direccion": "Av. Diagonal 100",
"codigo_municipio": "08019", "nombre_municipio": "Barcelona",
"codigo_postal": "08018", "pais": "ESP"
}
}
]
}
Respuesta — alta nueva
HTTP/1.1 201 Created
{
"ok": true,
"id": 4567,
"vehicle_id": 89,
"person_ids": [121, 122],
"license_ids": [55, 56],
"person_address_ids": [201, 202],
"address_ids": { "pickup": 203, "dropoff": 204 },
"mir_status": "pending"
}
Respuesta — reintento idempotente
HTTP/1.1 200 OK
{
"ok": true,
"id": 4567,
"idempotent": true,
"vehicle": { /* ... */ },
"persons": [ /* ... */ ]
}
Validaciones aplicadas
- Al menos un objeto en
persons; máximo tres. - Cada persona requiere
rolcon valorTI,CPoCS. - No se permiten roles duplicados dentro del mismo contrato.
- Fechas en formato
YYYY-MM-DD. - Correos validados con formato RFC 5322.
- El
establecimiento_iddebe pertenecer a la cuenta autenticada.
Vehículos
Cada contrato rent-a-car tiene exactamente un vehículo asociado.
Filtros: q sobre matricula y numero_bastidor; contract_id para filtrar por contrato.
Cuerpo
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| alquiler_id | integer | sí | Contrato al que se asocia el vehículo. |
| categoria | string | opcional | Por ejemplo TURISMO_M1, FURGON_N1. |
| tipo | string | opcional | Por ejemplo TURISMO, FURGONETA, MOTOCICLETA. |
| marca | string | opcional | |
| modelo | string | opcional | |
| matricula | string | opcional | |
| numero_bastidor | string | opcional | VIN. |
| color | string | opcional | |
| km_recogida | integer | opcional | |
| km_devolucion | integer | opcional | |
| datos_gps | string | opcional | Identificador del dispositivo GPS si aplica. |
| uuid | string (uuid) | opcional |
Personas
Titulares y conductores asociados a un contrato rent-a-car.
Filtros: q sobre nombre, apellido1, apellido2, numero_documento y correo; contract_id para filtrar por contrato.
Cuerpo
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| alquiler_id | integer | sí | |
| rol | enum | sí | TI, CP o CS. |
| nombre | string | opcional | |
| apellido1 | string | opcional | |
| apellido2 | string | opcional | |
| tipo_documento | string | opcional | NIF, NIE, PAS, OTRO o CIF. |
| numero_documento | string | opcional | |
| fecha_nacimiento | date | opcional | |
| nacionalidad | string (3) | opcional | ISO 3166-1 alpha-3. |
| sexo | enum | opcional | H, M u O. |
| telefono | string | opcional | |
| telefono2 | string | opcional | |
| correo | opcional | ||
| uuid | string (uuid) | opcional |
Permisos de conducir
Permiso de conducir asociado a una persona del contrato.
Cuerpo
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| persona_id | integer | sí | |
| tipo | string | opcional | Categorías estándar: AM, A1, A2, A, B, B1, BE, C1, C, D1, D. |
| validez | date | opcional | Fecha de caducidad. |
| numero | string | opcional | Número de permiso. |
| soporte | string | opcional | Número de soporte del documento. |
| uuid | string (uuid) | opcional |
Direcciones
Las direcciones de tipo recogida y devolucion se asocian
al contrato; las de tipo persona se asocian a la persona.
Cuerpo
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| tipo | enum | sí | recogida, devolucion o persona. |
| alquiler_id | integer | — | Obligatorio si tipo es recogida o devolucion. |
| persona_id | integer | — | Obligatorio si tipo es persona. |
| direccion | string | opcional | |
| direccion_complementaria | string | opcional | |
| codigo_municipio | string (5) | opcional | Código INE. |
| nombre_municipio | string | opcional | |
| codigo_postal | string | opcional | |
| pais | string (3) | opcional | ISO 3166-1 alpha-3. |
| uuid | string (uuid) | opcional |
Envío al Ministerio del Interior
La API es asíncrona respecto al envío al MIR. Una vez creado un contrato o un alta de huésped, la respuesta es inmediata y los datos quedan registrados en la plataforma. Un proceso interno se encarga de comunicarlos a la sede electrónica del Ministerio del Interior (SES.Hospedajes / Sistema VUD) siguiendo los mismos plazos y reglas que los registros creados desde la interfaz web.
Estados posibles del campo enviado_ministerio:
| Valor | Significado |
|---|---|
0 | Pendiente de envío al MIR. |
1 | Enviado al MIR. |
2 | Registro de sandbox. Nunca se enviará al MIR. |
La respuesta de POST /v1/rentacar/contracts incluye también
mir_status como información de conveniencia:
"pending"en producción — el envío al MIR se procesa de forma diferida."sandbox"cuando la API Key es de sandbox.
Seguimiento de estado
Para conocer el estado actual de un contrato o huésped, basta con consultar su detalle:
GET /v1/contracts/{id}
GET /v1/guests/{id}
La respuesta incluye el campo enviado_ministerio con los
valores descritos arriba. Una integración robusta puede polear el detalle
tras crear un registro para confirmar la transición a 1.
Changelog
- Nuevo endpoint atómico
POST /v1/rentacar/contractspara alta completa de contrato rent-a-car (contrato, vehículo, personas, permisos y direcciones en una sola transacción). - Nuevos CRUDs:
/v1/vehicles,/v1/persons,/v1/licenses,/v1/addresses. - Soporte de idempotencia (
uuid) extendido a todos los recursos rent-a-car. - Modo sandbox: las API Keys marcadas como sandbox permiten ejercitar la API sin enviar datos al Ministerio del Interior. La respuesta de
/v1/pingexponeenvysandbox. - Corrección de error que afectaba a
GET /v1/establishmentsal filtrar porq. - Documentación reescrita y especificación OpenAPI 3.0.3 publicada.
- Filtros
q,from,toy paginación en todos los listados. - Idempotencia en altas de contratos, huéspedes y establecimientos.