Integración
Cerraduras
Para quien construye el puente entre yaReserva y el sistema de cerraduras de un hotel. Aquí el que llama somos nosotros: tú expones tres endpoints y verificas nuestra firma.
Cómo funciona
yaReserva no maneja cerraduras. Lo que hace es avisar al puente del hotel en tres momentos, y el puente habla con Salto KS, TTLock, Dormakaba/Saflok, Assa Abloy Vostio o el sistema que sea.
| Momento | Qué pedimos |
|---|---|
| Check-in | Emitir una llave para la habitación, válida hasta la hora de salida. |
| Cambio de habitación | Revocar la llave del cuarto que deja y emitir la del nuevo. |
| Check-out | Revocar las llaves vivas de la reserva. |
Recepción también puede emitir una llave extra o revocar una desde la pantalla de la reserva.
Regla: Si tu puente falla, el mostrador sigue
El check-in, el check-out y el cambio de habitación siguen adelante aunque no haya llave. Recepción ve un aviso y puede reintentar desde la reserva. Un puente caído no puede dejar a un huésped esperando en el mostrador.
Alta de la conexión
El hotel crea la conexión en su panel, en Configuración → Cerraduras. Elige una propiedad, el tipo «Puente por webhook» y la URL base de tu puente, que tiene que ser https y apuntar a una IP pública. Ahí recibe, una sola vez, el par de credenciales.
| Dato | Ejemplo | Uso |
|---|---|---|
| keyId | yrlock_3f9a1c0b7d2e4a6f8b0c1d2e | Público. Viaja en cada petición que te hacemos. |
| secret | yrlock_sk_9c1f… (64 hex) | Secreto. Sirve para verificar la firma. Nunca viaja en las peticiones. |
Regla: El secreto se ve una sola vez
El panel lo enseña al crear la conexión y al rotarla, y no lo vuelve a enseñar. El hotel puede rotarlo cuando quiera; el anterior deja de valer en el acto, así que tu puente tiene que poder cambiarlo sin desplegar.
Después, el hotel mapea cada habitación con el id de su cerradura en el sistema del proveedor, el «lockId». Es lo que te mandamos para que sepas qué puerta abrir.
Dato: También existe el tipo Manual
No llama a nadie. Recepción graba la tarjeta en su propio codificador y yaReserva solo apunta quién tiene llave y hasta cuándo. Sirve para hoteles cuyo sistema de cerraduras no tiene forma de integrarse.
Cómo verificar nuestras peticiones
Las tres llamadas son POST con Content-Type: application/json a tu URL base más una ruta. Todas llevan los mismos headers.
X-YR-Lock-Key: <keyId>
X-YR-Lock-Timestamp: <segundos Unix, UTC>
X-YR-Lock-Signature: sha256=<hex(HMAC-SHA256(secret, timestamp + "." + cuerpo))>
User-Agent: yaReserva-Locks/1- Busca el secreto por X-YR-Lock-Key.
- Rechaza si el timestamp difiere de tu reloj en más de cinco minutos. Sincroniza con NTP.
- Calcula el HMAC sobre los bytes exactos del cuerpo recibido, sin re-serializar el JSON, y compáralo en tiempo constante.
- Contesta 401 si algo no cuadra, sin procesar nada.
const crypto = require('crypto');
function verificar(req, rawBody, secret) {
const ts = req.headers['x-yr-lock-timestamp'];
if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false;
const esperada =
'sha256=' +
crypto.createHmac('sha256', secret).update(`${ts}.`).update(rawBody).digest('hex');
const recibida = req.headers['x-yr-lock-signature'] || '';
return (
recibida.length === esperada.length &&
crypto.timingSafeEqual(Buffer.from(recibida), Buffer.from(esperada))
);
}SECRET=yrlock_sk_...
BODY='{"keyId":"yrlock_3f9a1c0b7d2e4a6f8b0c1d2e"}'
TS=$(date +%s)
SIG=$(printf '%s.%s' "$TS" "$BODY" | openssl dgst -sha256 -hmac "$SECRET" -hex | sed 's/^.* //')
curl -X POST https://puente.hotel.mx/locks/ping \
-H "Content-Type: application/json" \
-H "X-YR-Lock-Key: yrlock_3f9a1c0b7d2e4a6f8b0c1d2e" \
-H "X-YR-Lock-Timestamp: $TS" \
-H "X-YR-Lock-Signature: sha256=$SIG" \
--data-binary "$BODY"Cuidado: Guarda el cuerpo crudo antes de parsearlo
La mayoría de los frameworks parsean el JSON y tiran los bytes originales. Si firmas sobre el objeto re-serializado, la firma no coincide en cuanto el orden de las claves o un espacio cambien. Configura tu servidor para conservar el raw body de estas rutas.
Emitir una llave
{base}/issueLo llamamos al hacer check-in, al cambiar de habitación y cuando recepción pide una llave extra.
Lo que te mandamos
| Nombre | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| reference | UUID | Sí | Nuestro id de la llave. Úsalo como clave de idempotencia: si llega dos veces, devuelve la misma llave en lugar de emitir otra. |
| lockId | string | Sí | Lo que el hotel puso en el mapeo de esa habitación. |
| roomNumber | string | Sí | El número de habitación, para tus registros. |
| guest.name | string | Sí | Nombre del huésped. |
| guest.email | string | No | Puede faltar. Sirve para mandar una llave móvil y no se debe guardar para otro fin. |
| guest.phone | string | No | Igual que el correo: puede faltar, y solo para la llave móvil. |
| validFrom | ISO 8601 | Sí | Desde cuándo abre. En UTC, RFC 3339. |
| validUntil | ISO 8601 | Sí | Nunca pasa del día de salida a la hora de check-out del hotel, en su zona horaria. |
Petición
{
"reference": "7b0c5d2e-1f3a-4c6b-9d8e-2a1b3c4d5e6f",
"lockId": "SALTO-204",
"roomNumber": "204",
"guest": { "name": "Ana Ruiz", "email": "ana@correo.mx", "phone": "+525512345678" },
"validFrom": "2026-11-20T21:04:00Z",
"validUntil": "2026-11-22T18:00:00Z"
}Respuesta
{
"externalId": "K-889123",
"pinCode": "482913",
"mobileKeyUrl": "https://llave.proveedor.com/k/889123"
}Lo que devuelves
| Nombre | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| externalId | string | Sí | Id de la llave en tu sistema, de hasta 200 caracteres. Es lo que te mandamos al revocar. |
| pinCode | string | No | PIN del teclado, hasta 32 caracteres. Se lo enseñamos a recepción una sola vez y solo guardamos sus últimos cuatro dígitos. |
| mobileKeyUrl | string | No | Tiene que ser https. Se enseña a recepción para compartirla con el huésped. |
Cuidado: Sin externalId, la damos por fallida
Si la respuesta no trae externalId, o trae un mobileKeyUrl que no es https, la tomamos como fallida y te mandamos un revoke con el externalId si es que venía. Devuelve siempre el id, aunque la llave la resuelvas después.
Revocar una llave
{base}/revokeLo llamamos al hacer check-out, al cambiar de habitación y cuando recepción revoca a mano.
Lo que te mandamos
| Nombre | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| externalId | string | Sí | El id que devolviste al emitir la llave. |
Petición
{ "externalId": "K-889123" }Respuesta
200 OK · la llave ya no abre
204 · lo mismo, sin cuerpo
404 · cuenta como revocada: esa llave ya no existe en tu sistemaRevocar dos veces tiene que ser inofensivo. Un 404 lo leemos como éxito, no como error: si la llave no existe, desde luego no abre.
Probar la conexión
{base}/pingLo que corre el botón «Probar conexión» del panel del hotel. Responde 200 si la firma es válida y tu puente llega al sistema de cerraduras.
Lo que te mandamos
| Nombre | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| keyId | string | Sí | La llave pública de la conexión que se está probando. |
Petición
{ "keyId": "yrlock_3f9a1c0b7d2e4a6f8b0c1d2e" }Contesta 200 solo si de verdad llegas al sistema de cerraduras. Un ping que siempre dice que sí deja al hotel creyendo que todo está bien hasta el primer check-in.
Errores
Cualquier respuesta fuera de 2xx —salvo el 404 de revoke— es un fallo. Si mandas un cuerpo JSON con «message» o «error», se lo enseñamos a recepción recortado a 200 caracteres. No incluyas datos personales ni secretos en ese texto.
{ "message": "cerradura 204 sin batería" }| Situación | Qué hacemos |
|---|---|
| Sin respuesta en 10 segundos, error TLS o conexión rechazada | Fallo, y aviso a recepción. |
| Una redirección 3xx | Fallo. No seguimos redirecciones. |
| Un 4xx o un 5xx | Fallo, con tu «message» a la vista. |
| Cuerpo de más de 64 KB o JSON inválido | Fallo. |
Reintentos
Regla: No reintentamos solos
Así un puente lento no bloquea el mostrador y se evitan llaves duplicadas. Quien decide reintentar es recepción, desde la reserva.
- Check-in con fallo: el huésped entra igual y recepción ve el aviso LOCK_SYSTEM_ERROR. Reintenta con «Emitir llave» desde la reserva. Cada reintento lleva un reference nuevo; si tu sistema ya había emitido la anterior, quedará viva hasta su validUntil.
- Check-out con fallo: el huésped sale igual. La llave sigue marcada como activa hasta que recepción la revoque o llegue su validUntil, que es la hora de salida.
- Revocar a mano con fallo: te devolvemos el error. Recepción puede forzar la revocación, por ejemplo si la tarjeta se destruyó. En ese caso la apuntamos como revocada junto con el error de tu sistema, y la cerradura puede seguir abriendo hasta validUntil.
- Cambio de habitación: primero revocamos la llave vieja y después emitimos la nueva. Si la revocación falla, emitimos igual y avisamos.
Cuando tu sistema tenga su propio reintento hacia la cerradura —por ejemplo, un gateway sin red— contesta 2xx en cuanto aceptes la orden y resuélvela después. Nosotros solo necesitamos el externalId.
Seguridad
- Llamamos únicamente a URLs https que resuelvan a IPs públicas. Las privadas, loopback, link-local y CGNAT se rechazan también al conectar, no solo al guardar.
- El secreto se guarda cifrado con AES-256-GCM. Si sospechas una fuga, pide al hotel que lo rote.
- El PIN completo no se guarda en yaReserva: solo sus últimos cuatro dígitos, para que recepción lo reconozca sin poder volver a leerlo.
¿Vas a integrar un hotel?
Las credenciales salen del panel del hotel, y las de sandbox se crean el mismo día. Si el hotel todavía no tiene cuenta, empieza por registrarlo.