SES.Hospedajes API

Referencia técnica para integradores — versión 1.2.0

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

  1. El propietario de la cuenta debe disponer de plan Premium con la API habilitada.
  2. 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).
  3. Toda llamada incluye la cabecera X-Api-Key: <tu_api_key>.
  4. La base URL es https://seshospedajes.es/app/api/v1.
  5. 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:

  1. Cabecera X-Api-Key: <clave> recomendado
  2. Cabecera Api-Key: <clave>
  3. 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'
<?php
$ch = curl_init('https://seshospedajes.es/app/api/v1/establishments');
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER => ['X-Api-Key: TU_API_KEY'],
]);
$response = curl_exec($ch);
$data = json_decode($response, true);
curl_close($ch);
const res = await fetch('https://seshospedajes.es/app/api/v1/establishments', {
  headers: { 'X-Api-Key': 'TU_API_KEY' }
});
const data = await res.json();
import requests

response = requests.get(
    'https://seshospedajes.es/app/api/v1/establishments',
    headers={'X-Api-Key': 'TU_API_KEY'},
)
data = response.json()

Códigos de error de autenticación

HTTPcodeDescripción
401auth_missingNo se proporcionó API Key.
401auth_invalidLa API Key no existe.
401auth_inactiveLa API Key existe pero está desactivada.
403plan_requiredEl plan de la cuenta no incluye acceso a la API.
403api_disabledLa 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:

Los contratos creados con una API Key de sandbox quedan marcados con 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 env en ping y 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ámetroTipoPor defectoDescripción
pageinteger1Número de página, empezando por 1.
limitinteger20Tamaño de página. Máximo 200.
qstringBúsqueda textual. Campos cubiertos detallados en cada endpoint.
fromdate (YYYY-MM-DD)Filtro de fecha mínima. Campo de fecha aplicado: ver cada endpoint.
todate (YYYY-MM-DD)Filtro de fecha máxima. Inclusivo.
contract_idintegerSolo 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:

EndpointClave natural de idempotencia
POST /v1/contractsreferencia + cuenta del propietario.
POST /v1/guestsnumero_documento + fecha_entrada + establecimiento_id.
POST /v1/rentacar/contractsuuid 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:SS en 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: 28079 para 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"
  }
}
HTTPcodeDescripción
400bad_jsonEl cuerpo de la petición no es JSON válido.
400no_changesEl cuerpo de un PUT/PATCH no contiene campos modificables.
401auth_missingFalta cabecera de autenticación.
401auth_invalidAPI Key no encontrada.
401auth_inactiveAPI Key desactivada.
403plan_requiredEl plan de la cuenta no permite usar la API.
403api_disabledLa API no está habilitada para la cuenta.
403forbiddenEl recurso solicitado no pertenece a la cuenta autenticada.
404not_foundEl recurso o la ruta no existen.
405method_not_allowedVerbo HTTP no permitido en la ruta.
422missing_fieldsFaltan campos obligatorios. Detalle en fields (array).
422validation_errorAlgún campo tiene un formato inválido. Detalle en fields (objeto).
500server_errorError inesperado. Las altas atómicas garantizan que no queden registros parciales.
500db_connectIndisponibilidad 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 uuid en 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

GET /v1/ping

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.

GET /v1/establishments

Listado de establecimientos de la cuenta. Filtros: q sobre nombre y numero_establecimiento.

POST /v1/establishments

Cuerpo

CampoTipoObligatorioDescripción
nombrestringNombre del establecimiento.
numero_establecimientostringCódigo asignado por el Ministerio del Interior.
uuidstring (uuid)opcionalPara idempotencia.

Ejemplo

{
  "nombre": "Oficina Aeropuerto T1",
  "numero_establecimiento": "R12345"
}
GETPUTDELETE /v1/establishments/{id}

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.

GET /v1/guests

Filtros: q sobre nombre, apellido1, apellido2, numero_documento, contacto_email. from/to sobre fecha_entrada.

POST /v1/guests

Cuerpo

CampoTipoObligatorioDescripción
nombrestring
apellido1string
apellido2stringopcional
establecimiento_idintegerDebe pertenecer a la cuenta.
tipo_documentoenumopcionalDNI, NIE o PASAPORTE.
numero_documentostringopcional
fecha_nacimientodateopcionalYYYY-MM-DD.
nacionalidadstring (3)opcionalISO 3166-1 alpha-3.
generoenumopcionalM, F u Otro.
contacto_emailemailopcional
contacto_telefonostringopcional
fecha_entradadateopcionalYYYY-MM-DD.
hora_entradatimeopcionalHH:MM:SS.
fecha_salidadateopcional
hora_salidatimeopcional
habitacionstringopcional
uuidstring (uuid)opcionalIdempotencia.
GETPUTDELETE /v1/guests/{id}

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.

GET /v1/contracts

Filtros: q sobre referencia y numero_establecimiento. from/to sobre fecha_contrato.

POST /v1/contracts

Cuerpo

CampoTipoObligatorioDescripción
establecimiento_idinteger
referenciastringIdentificador del contrato. Único por cuenta.
fecha_contratodateopcional
fecha_recogidadatetimeopcional
fecha_devoluciondatetimeopcional
tipo_pagostringopcionalPor ejemplo TARJETA, EFECTIVO.
fecha_pagodateopcional
medio_pagostringopcional
titular_pagostringopcional
caducidad_tarjetastringopcionalFormato MM/AA.
codigo_establecimiento_mirstringopcionalSi difiere del registrado en el establecimiento.
uuidstring (uuid)opcionalIdempotencia.
GETPUTDELETE /v1/contracts/{id}

Precheckins (solo lectura)

GET /v1/precheckins

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:

RecursoCardinalidad por contratoDescripción
Contrato (contract)1Cabecera: referencia, fechas, datos de pago.
Vehículo (vehicle)1Vehículo asignado al contrato.
Persona (person)1 a 3Titular (rol TI), conductor principal (CP) y conductor secundario opcional (CS).
Permiso de conducir (license)0 o 1 por personaDatos del carnet del conductor.
Dirección de persona (address tipo persona)0 o 1 por personaDomicilio personal del conductor.
Dirección de recogida (pickup_address)0 o 1Localización donde se retira el vehículo.
Dirección de devolución (dropoff_address)0 o 1Localización donde se entrega el vehículo.

Roles de persona

CódigoRol
TITitular del contrato
CPConductor principal
CSConductor secundario

Cada rol puede aparecer como máximo una vez por contrato.

Alta de contrato rent-a-car (transacción única)

POST /v1/rentacar/contracts

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

CampoTipoObligatorioDescripción
uuidstring (uuid)opcionalIdempotencia del envoltorio.
contractobjectCabecera del contrato. Ver tabla en /v1/contracts.
vehicleobjectDatos del vehículo. Ver /v1/vehicles.
personsarray (1–3)Cada elemento es una persona; admite license y address anidados.
pickup_addressobjectopcionalDirección de recogida del vehículo.
dropoff_addressobjectopcionalDirecció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 rol con valor TI, CP o CS.
  • No se permiten roles duplicados dentro del mismo contrato.
  • Fechas en formato YYYY-MM-DD.
  • Correos validados con formato RFC 5322.
  • El establecimiento_id debe pertenecer a la cuenta autenticada.

Vehículos

Cada contrato rent-a-car tiene exactamente un vehículo asociado.

GET /v1/vehicles

Filtros: q sobre matricula y numero_bastidor; contract_id para filtrar por contrato.

POST /v1/vehicles

Cuerpo

CampoTipoObligatorioDescripción
alquiler_idintegerContrato al que se asocia el vehículo.
categoriastringopcionalPor ejemplo TURISMO_M1, FURGON_N1.
tipostringopcionalPor ejemplo TURISMO, FURGONETA, MOTOCICLETA.
marcastringopcional
modelostringopcional
matriculastringopcional
numero_bastidorstringopcionalVIN.
colorstringopcional
km_recogidaintegeropcional
km_devolucionintegeropcional
datos_gpsstringopcionalIdentificador del dispositivo GPS si aplica.
uuidstring (uuid)opcional
GETPUTDELETE /v1/vehicles/{id}

Personas

Titulares y conductores asociados a un contrato rent-a-car.

GET /v1/persons

Filtros: q sobre nombre, apellido1, apellido2, numero_documento y correo; contract_id para filtrar por contrato.

POST /v1/persons

Cuerpo

CampoTipoObligatorioDescripción
alquiler_idinteger
rolenumTI, CP o CS.
nombrestringopcional
apellido1stringopcional
apellido2stringopcional
tipo_documentostringopcionalNIF, NIE, PAS, OTRO o CIF.
numero_documentostringopcional
fecha_nacimientodateopcional
nacionalidadstring (3)opcionalISO 3166-1 alpha-3.
sexoenumopcionalH, M u O.
telefonostringopcional
telefono2stringopcional
correoemailopcional
uuidstring (uuid)opcional
GETPUTDELETE /v1/persons/{id}

Permisos de conducir

Permiso de conducir asociado a una persona del contrato.

POST /v1/licenses

Cuerpo

CampoTipoObligatorioDescripción
persona_idinteger
tipostringopcionalCategorías estándar: AM, A1, A2, A, B, B1, BE, C1, C, D1, D.
validezdateopcionalFecha de caducidad.
numerostringopcionalNúmero de permiso.
soportestringopcionalNúmero de soporte del documento.
uuidstring (uuid)opcional
GETPUTDELETE /v1/licenses/{id}

Direcciones

Las direcciones de tipo recogida y devolucion se asocian al contrato; las de tipo persona se asocian a la persona.

POST /v1/addresses

Cuerpo

CampoTipoObligatorioDescripción
tipoenumrecogida, devolucion o persona.
alquiler_idintegerObligatorio si tipo es recogida o devolucion.
persona_idintegerObligatorio si tipo es persona.
direccionstringopcional
direccion_complementariastringopcional
codigo_municipiostring (5)opcionalCódigo INE.
nombre_municipiostringopcional
codigo_postalstringopcional
paisstring (3)opcionalISO 3166-1 alpha-3.
uuidstring (uuid)opcional
GETPUTDELETE /v1/addresses/{id}

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:

ValorSignificado
0Pendiente de envío al MIR.
1Enviado al MIR.
2Registro 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

v1.2.0 — 2026-06-25
  • Nuevo endpoint atómico POST /v1/rentacar/contracts para 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/ping expone env y sandbox.
  • Corrección de error que afectaba a GET /v1/establishments al filtrar por q.
  • Documentación reescrita y especificación OpenAPI 3.0.3 publicada.
v1.1
  • Filtros q, from, to y paginación en todos los listados.
  • Idempotencia en altas de contratos, huéspedes y establecimientos.