API de OmniStay
Versión 1 · Última actualización: 22 de octubre de 2026
Conecta tus otros programas a OmniStay: contabilidad, panel de control, herramienta de mantenimiento, Zapier o Make. La API da acceso a tus alojamientos, reservas, tareas, propietarios y a tu equipo, y permite actuar: tareas, presupuestos, facturas, calendario, precios… Los webhooks avisan a tus programas en cuanto llega una reserva, un mensaje o una tarea. Tu IA (ChatGPT, Claude, Gemini) también se conecta, mediante el servidor MCP.
En resumen
- Dirección base:
https://escale-roan.vercel.app/api/v1 - Formato: JSON en UTF-8. Las fechas tienen el formato
AAAA-MM-JJ, las horasHH:MM(hora de París) y los importes van en euros. - Autenticación: una clave API de tu empresa en la cabecera
Authorization: Bearer esk_…. - Permisos: cada clave es de solo lectura, o de lectura y escritura (para actuar: crear tareas y las 91 acciones).
- IA conectadas: servidor MCP en la dirección
https://app.omnistay.ai/mcp, conexión OAuth o mediante clave API (detalles). - Límite: 120 llamadas por minuto y por clave.
Crear una clave
- En OmniStay, abre Ajustes › Claves API. Solo la propietaria y los administradores de la cuenta tienen acceso.
- Pon a la clave el nombre del programa que vas a conectar, y autoriza la escritura solo si ese programa tiene que actuar en OmniStay.
- Copia la clave enseguida: empieza por
esk_y solo se muestra una vez. OmniStay solo guarda una huella. - ¿Una clave que ya no se usa, o que alguien más ha podido ver? Revócala. Deja de funcionar al instante.
Autenticarse
Cada llamada lleva la clave. Para comprobar que funciona:
curl https://escale-roan.vercel.app/api/v1/me \
-H "Authorization: Bearer esk_VOTRE_CLE"
{
"data": {
"organization": { "id": "11111111-1111-4111-8111-111111111111", "name": "Les Clés du Canal" },
"key": { "name": "Comptabilité", "prefix": "esk_Ab12Cd", "scopes": ["read"] }
}
}
También se acepta la cabecera X-Api-Key: esk_….
Recursos
| Método | Dirección | Lo que devuelve |
|---|---|---|
| GET | /me | Tu empresa y la clave utilizada |
| GET | /properties, /properties/{id} | Alojamientos |
| GET | /bookings, /bookings/{id} | Reservas |
| GET | /missions, /missions/{id} | Tareas: limpiezas, llaves, mantenimiento… |
| POST | /missions | Crea una tarea (clave con permiso de escritura) |
| GET | /actions | Las 91 acciones, con el esquema de sus parámetros |
| POST | /actions/{nom} | Ejecuta una acción (clave con permiso de escritura para actuar) |
| POST | /webhooks | Suscribe una dirección a eventos (webhooks) |
| GET | /webhooks, /webhooks/{id} | Las suscripciones creadas con esta clave |
| DELETE | /webhooks/{id} | Elimina una suscripción |
| GET | /owners, /owners/{id} | Propietarios |
| GET | /team, /team/{id} | Equipo |
Alojamientos
GET /properties
{
"data": [{
"id": "p1", "name": "Loft Canal Saint-Martin", "internal_name": "Valmy 3e G", "type": "appartement", "status": "active",
"address": { "street": "42 quai de Valmy", "zip": "75010", "city": "Paris" },
"surface_m2": 58,
"capacity": { "guests": 4, "double_beds": 1, "single_beds": 0, "sofa_beds_double": 1, "sofa_beds_single": 0 },
"check_in": { "from": "16:00", "until": "23:00", "mode": "lockbox" }, "check_out": "11:00",
"platforms": ["airbnb", "booking"], "base_price": 145, "cleaning_fee": 70,
"owner_id": "c1", "created_at": "2026-10-17", "updated_at": "2026-10-17T09:12:44.512Z"
}],
"total": 6, "limit": 100, "offset": 0
}
La API nunca devuelve los códigos de acceso (caja de llaves, cerradura) ni el Wi-Fi.
Reservas
GET /bookings?from=2026-10-01&to=2026-11-01&property_id=p1
| Filtro | Efecto |
|---|---|
from, to | Las reservas que tocan el periodo: salida después de from, llegada antes de to |
property_id | Un solo alojamiento |
status | confirmed ou cancelled |
updated_since | Solo lo que ha cambiado desde una fecha y una hora ISO 8601 (2026-10-17T09:00:00Z): práctico para sincronizar |
{
"data": [{
"id": "cx_8f2a", "property_id": "p1", "platform": "airbnb", "reference": "HMX4K2P9QA", "status": "confirmed",
"check_in": "2026-10-17", "check_out": "2026-10-21", "nights": 4, "arrival_time": "16:30", "departure_time": null,
"guest": { "first_name": "Camille", "last_name": "Laurent", "email": "camille@exemple.fr", "phone": "+33 6 12 34 56 78",
"language": "fr", "country": "France", "count": 2 },
"amounts": { "currency": "EUR", "guest_paid": 690.8, "accommodation": 600, "nightly": 150, "cleaning": 70, "linen": 15,
"tourist_tax": 20.8, "platform_fees": 103.85, "payout": 566.15, "tax_collected_by_platform": true },
"created_at": "2026-09-30", "updated_at": "2026-10-16T18:02:11.870Z"
}],
"total": 1, "limit": 100, "offset": 0
}
El día de salida (check_out) no es una noche reservada. platform vale airbnb, booking, vrbo, expedia, direct o manual.
Tareas
GET /missions?from=2026-10-20&to=2026-10-31&type=cleaning
Filtros: from y to (fecha de la tarea, incluidas), property_id, member_id, type, status, updated_since.
{
"data": [{
"id": "cl_8f2a", "type": "cleaning", "title": "Ménage de fin de séjour", "description": null,
"property_id": "p1", "booking_id": "cx_8f2a", "member_id": "t1",
"date": "2026-10-21", "time": "11:00", "duration": "02:30", "pay": 55, "billed": 70, "status": "accepted",
"report": null, "created_at": "2026-09-30", "updated_at": "2026-10-16T18:02:12.004Z"
}],
"total": 1, "limit": 100, "offset": 0
}
| Campo | Valores |
|---|---|
type | cleaning (limpieza), keys (llaves), diy, linen, plumbing, electricity, photo, delivery, pool, tour, decoration, pests, hvac, taxi, massage, food, babysitting, pets, housekeeper, other |
status | unassigned, offered (propuesta), accepted, done (hecha, por validar), validated, cancelled |
pay, billed | Pagado a la persona que interviene, y refacturado al propietario (euros) |
report | Después de la tarea: número de fotos, comentario, duración en minutos, objetos que faltan y daños |
Crear una tarea
Con una clave que tenga permiso de escritura. La tarea se propone a la persona elegida (member_id) o, si no, al equipo del alojamiento; la persona la acepta en su app, y la tarea aparece al instante en OmniStay.
curl -X POST https://escale-roan.vercel.app/api/v1/missions \
-H "Authorization: Bearer esk_VOTRE_CLE" \
-H "Content-Type: application/json" \
-d '{ "type": "plumbing", "property_id": "p1", "date": "2026-10-18", "time": "09:00",
"member_id": "t2", "description": "Fuite sous l’évier de la cuisine" }'
| Campo | Obligatorio | Por defecto |
|---|---|---|
property_id | Sí | — |
date | Sí | — |
type | No | cleaning |
time | No | Hora de salida del alojamiento para una limpieza, 16:00 para las llaves, 10:00 en los demás casos |
duration | No | Duración de la limpieza del alojamiento; si no, 02:00 |
pay, billed | No | Ajustes del alojamiento para una limpieza |
member_id, booking_id | No | Ninguno |
title, description | No | El nombre del tipo de tarea |
Respuesta 201 con la tarea creada, en el mismo formato que GET /missions.
Acciones
Todo lo que el Asistente de IA sabe hacer en OmniStay pasa también por la API: 91 acciones (presupuestos, facturas, reservas, calendario, precios, tareas, equipo y ausencias, propietarios, alojamientos, mensajes, reseñas, fianzas, incidencias, daños y disputas, prospectos, estimaciones de ingresos, recepción de los huéspedes y mensajes programados, tasa turística, estadísticas de reservas y previsión…), con los mismos controles: permisos de la persona que creó la clave, registro y anulación durante 24 horas desde la app. La lista, con el esquema JSON de los parámetros de cada una:
curl https://escale-roan.vercel.app/api/v1/actions \
-H "Authorization: Bearer esk_VOTRE_CLE"
{ "data": [{ "name": "creer_devis", "title": "Créer un devis", "module": "Facturation", "kind": "write", "confirmation": false,
"description": "…", "input_schema": { "type": "object", "properties": { … } },
"method": "POST", "path": "/api/v1/actions/creer_devis" }], "total": 91 }
Para ejecutar una acción, envía sus parámetros en JSON:
curl -X POST https://escale-roan.vercel.app/api/v1/actions/creer_devis \
-H "Authorization: Bearer esk_VOTRE_CLE" \
-H "Content-Type: application/json" \
-d '{ "client": "Sophie Martin", "objet": "Ménage de printemps",
"lignes": [{ "designation": "Grand ménage", "prix_unitaire": 120 }] }'
{ "status": "done", "message": "Devis en brouillon pour Sophie Martin : « Ménage de printemps »…",
"data": { "id": "doc_…" }, "url": "https://app.omnistay.ai/app/#/facturation/document/doc_…", "journal_id": "…" }
- Respuesta
201cuando la acción se ha hecho ("status": "done"),200para una lectura ("status": "ok"). - Añade
"dry_run": truepara ver lo que haría la acción, sin cambiar nada: respuesta"status": "preview"con la vista previa. - Las acciones
"confirmation": trueenvían algo o no se pueden deshacer (emitir una factura, enviar un mensaje, calendario y precios enviados a las plataformas, cobrar una fianza…). A través de la API, se ejecutan en cuanto se llaman: pruébalas antes condry_run. - Las acciones
"kind": "write"requieren una clave con permiso de escritura. Nunca hay códigos de acceso ni contraseñas de Wi-Fi en las respuestas.
IA conectadas (MCP)
OmniStay es un servidor MCP (Model Context Protocol): ChatGPT, Claude, Gemini, Claude Code, Gemini CLI o tus propios agentes leen y actúan en OmniStay con las 91 acciones anteriores, en forma de herramientas. Controlar OmniStay desde una IA forma parte de la opción Asistente de IA.
- Dirección:
https://app.omnistay.ai/mcp(HTTP «streamable», respuestas JSON, sin sesión). - Versiones del protocolo: 2024-11-05, 2025-03-26, 2025-06-18, 2025-11-25 y 2026-07-28.
- Conexión OAuth 2.1 (ChatGPT, Claude, Gemini): descubrimiento mediante
/.well-known/oauth-protected-resourcey/.well-known/oauth-authorization-server, registro dinámico (/oauth/register) o documento de metadatos del cliente, PKCE S256 obligatorio, tokens vinculados al recurso y renovación con rotación. La persona inicia sesión, elige su empresa y puede autorizar solo la lectura; desconecta la IA con un clic en Ajustes › Claves API. - Conexión mediante clave API (Claude Code, Gemini CLI, tus agentes): cabecera
Authorization: Bearer esk_…. - Confirmación: las herramientas que envían algo o no se pueden deshacer tienen un parámetro
confirmer. Sin él, no hacen nada y devuelven una vista previa que empieza por «Rien n’est fait» (no se ha hecho nada); la IA se la muestra a la persona y vuelve a llamar a la herramienta con"confirmer": truetras su aprobación. - Registro: cada acción queda anotada en Ajustes › Diario de la IA, a nombre de la persona que conectó la IA, y se puede deshacer durante 24 horas. 120 llamadas por minuto y por IA conectada.
Claude Code:
claude mcp add --transport http omnistay https://app.omnistay.ai/mcp \
--header "Authorization: Bearer esk_VOTRE_CLE"
Gemini CLI, en ~/.gemini/settings.json:
{ "mcpServers": { "omnistay": { "httpUrl": "https://app.omnistay.ai/mcp",
"headers": { "Authorization": "Bearer esk_VOTRE_CLE" } } } }
ChatGPT, Claude y Gemini: los pasos, actualizados, están en OmniStay, Ajustes › Claves API.
Webhooks
OmniStay avisa a tu programa en cuanto ocurre algo: envía un POST en JSON a la dirección que indiques. Suscríbete en la app (Ajustes › Integraciones, con «Enviar una prueba» y los últimos envíos) o mediante la API con una clave, según el modelo «REST Hooks».
| Evento | Cuándo |
|---|---|
booking.created | Llega una reserva futura: plataforma, reserva directa o introducida a mano. Una reserva hecha en la web de una empresa de gestión o de un anfitrión se envía una vez pagada, nunca mientras espera el pago (ni si se cancela antes) |
booking.updated | Fechas, alojamiento, horas de llegada o de salida, huésped o importes modificados (varios cambios antes del envío: un solo envío, el más reciente) |
booking.cancelled | Se cancela una reserva |
precheckin.completed | El huésped ha rellenado su pre-check-in: data.precheckin (completed_at, guests, forms), nunca los partes de viajeros |
message.received | Un nuevo mensaje de un huésped, un envío por mensaje (text, translation, sent_at) |
review.received | Una nueva reseña: kind vale review (plataforma) o first_impression (app del huésped) |
incident.opened | Un huésped comunica un problema (agua caliente, llaves, Wi-Fi, fuga…) |
mission.created, mission.accepted, mission.done | Una tarea futura se crea, la acepta una persona del equipo o se termina (con su informe) |
invoice.issued | Una factura, una factura de anticipo o una rectificativa recibe su número: source vale invoicing (Facturación) u owner_statement (factura del mes de un propietario) |
lead.received | Alguien rellena el formulario de tu web corporativa |
Las estancias y tareas pasadas, las reseñas y los mensajes antiguos, y lo que añade una importación desde un software anterior no desencadenan nada.
Lo que recibe tu dirección
POST https://votre-outil.exemple.fr/omnistay
Content-Type: application/json; charset=utf-8
User-Agent: OmniStay-Webhooks/1.0
X-OmniStay-Event: booking.created
X-OmniStay-Event-Id: evt_6f1c0b7e2d4a4c1f9b3e8d5a7c2f1e09
X-OmniStay-Delivery: 1842
X-OmniStay-Signature: t=1792656000,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd
{
"id": "evt_6f1c0b7e2d4a4c1f9b3e8d5a7c2f1e09",
"type": "booking.created",
"created_at": "2026-10-22T09:14:03Z",
"test": false,
"organization": { "id": "11111111-1111-4111-8111-111111111111", "name": "Les Clés du Canal" },
"data": {
"id": "cx_8f2a", "property_id": "p1", "property": { "id": "p1", "name": "Loft Canal Saint-Martin" },
"platform": "airbnb", "reference": "HMX4K2P9QA", "status": "confirmed",
"check_in": "2026-10-24", "check_out": "2026-10-28", "nights": 4, "arrival_time": "16:30", "departure_time": null,
"guest": { "first_name": "Camille", "last_name": "Laurent", "email": "camille@exemple.fr", "phone": "+33 6 12 34 56 78",
"language": "fr", "country": "France", "count": 2 },
"amounts": { "currency": "EUR", "guest_paid": 690.8, "payout": 566.15, "…": "…" },
"created_at": "2026-10-22"
}
}
datasigue el formato de la API (reserva, tarea…), con el nombre del alojamiento (property), de la persona del equipo (member) o del huésped (guest). Nunca códigos de acceso, Wi-Fi, fianza ni parte de viajeros.- Responde con un código
2xxen menos de 8 segundos; las redirecciones no se siguen. - Un mismo evento puede llegar dos veces (nuevo intento):
idpermite ignorar un duplicado. El orden de llegada no está garantizado:created_atda el orden. - «Enviar una prueba», en la app, envía un ejemplo del evento elegido con
"test": truey datos de ejemplo: están todos los campos, para que Zapier o Make aprendan la forma de los datos.
Verificar la firma
La cabecera X-OmniStay-Signature vale t=<horodatage>,v1=<signature>. La firma es el HMAC-SHA256 (en hexadecimal) de <t>.<corps brut>, calculado con el secreto del webhook (whsec_…, que se da al crearlo y se ve en la app). Rechaza una marca de tiempo de más de 5 minutos.
import crypto from 'node:crypto';
// corps : le texte brut reçu, avant tout JSON.parse
function signatureValable(secret, entete, corps) {
const m = /^t=(\d+),v1=([0-9a-f]{64})$/.exec(entete || '');
if (!m || Math.abs(Date.now() / 1000 - Number(m[1])) > 300) return false;
const attendue = crypto.createHmac('sha256', secret).update(`${m[1]}.${corps}`).digest('hex');
return crypto.timingSafeEqual(Buffer.from(attendue), Buffer.from(m[2]));
}
Nuevos intentos y desactivación
- Sin respuesta
2xx: nuevo intento tras 1 min, 5 min, 30 min, 2 h y 8 h (6 intentos en total), con exactamente el mismo cuerpo y el mismoid. - 24 horas de fallos seguidos: el webhook se desactiva. Se reactiva en la app.
- Una respuesta
410 Gonelo desactiva al instante (modelo REST Hooks). - Revocar una clave desactiva los webhooks que creó. El historial de envíos se guarda 30 días.
Suscribirse mediante la API
| Método | Dirección | Efecto |
|---|---|---|
| POST | /webhooks | Crea una suscripción: { "url": "https://…", "events": ["booking.created"], "name": "…" } (también se aceptan target_url y event). Respuesta 201 con data y secret, que la API da una sola vez |
| GET | /webhooks, /webhooks/{id} | Las suscripciones creadas con esta clave, y la lista de eventos (events) |
| DELETE | /webhooks/{id} | Elimina una suscripción creada con esta clave |
curl -X POST https://escale-roan.vercel.app/api/v1/webhooks \
-H "Authorization: Bearer esk_VOTRE_CLE" \
-H "Content-Type: application/json" \
-d '{ "url": "https://votre-outil.exemple.fr/omnistay", "events": ["booking.created", "booking.cancelled"] }'
Basta con una clave de solo lectura. Solo direcciones https:// (puerto 443), nunca una dirección IP, local o interna; 20 webhooks como máximo por empresa.
Zapier y Make
OmniStay no tiene app oficial en Zapier ni en Make: la conexión se hace con los webhooks (para recibir avisos) y con la clave API (para actuar). Los pasos están en la app, Ajustes › Integraciones; el paso a paso, con tres ejemplos (reservas en Google Sheets, mensajes de los huéspedes en Slack, tarea creada desde un formulario), está en el centro de ayuda: «Conectar OmniStay a Zapier» y «Conectar OmniStay a Make».
| Recibir avisos | Actuar en OmniStay | |
|---|---|---|
| Zapier | «Webhooks by Zapier» › «Catch Hook» (planes de pago de Zapier) | «Webhooks by Zapier» › «Custom Request»: Method, URL, Data (JSON) y, en Headers, Authorization: Bearer esk_… |
| Make | «Webhooks» › «Custom webhook» | «HTTP» › «Make a request»: Authentication type «API key» (clave Bearer esk_… en la cabecera Authorization), cuerpo application/JSON |
Propietarios y equipo
GET /owners
{ "data": [{ "id": "c1", "civility": "Mme", "first_name": "Sophie", "last_name": "Martin", "email": "sophie@exemple.fr",
"phone": "06 12 34 56 78", "address": "8 rue Lepic, 75018 Paris", "commission": { "mode": "percent", "value": 20 },
"since": "2023-04-02", "property_ids": ["p1", "p2"] }], "total": 1, "limit": 100, "offset": 0 }
GET /team
{ "data": [{ "id": "t1", "first_name": "Fatima", "last_name": "B.", "role": "cleaning", "status": "active",
"property_ids": ["p1", "p2"] }], "total": 1, "limit": 100, "offset": 0 }
role vale cleaning, keys, maintenance u other. Los antiguos miembros del equipo no aparecen.
Listas y páginas
Las listas devuelven data, total, limit y offset. Por defecto, 100 elementos; limit llega hasta 500. Para la página siguiente, aumenta offset: ?limit=100&offset=100. Las reservas se ordenan por fecha de llegada, y las tareas por fecha y hora.
Errores
En caso de error, la respuesta contiene un código estable para tus programas y un mensaje en francés:
{ "error": { "code": "read_only_key", "message": "Cette clé est en lecture seule : créez une clé avec le droit d’écriture." } }
| Estado | Códigos | Significado |
|---|---|---|
| 400 | invalid_date, invalid_period, invalid_status, invalid_type, invalid_limit, invalid_offset, invalid_json | Un filtro o el cuerpo de la solicitud está mal formado |
| 401 | missing_key, invalid_key | Clave ausente, desconocida o revocada |
| 403 | read_only_key | La clave no tiene permiso de escritura |
| 404 | not_found | Dirección o elemento no encontrado |
| 405 | method_not_allowed | Método no admitido en esta dirección |
| 422 | property_required, unknown_property, unknown_member, unknown_booking, invalid_time, invalid_duration, invalid_amount, invalid_text | La tarea que se quiere crear no es válida |
| 403, 404, 409, 422 | read_only, forbidden, unknown_action, not_found, conflict, invalid_input, invalid_state, ambiguous, already_exists… | Acciones: permisos insuficientes, acción o elemento desconocido, elemento modificado entretanto (vuelve a intentarlo), parámetros por corregir, varios elementos posibles (precisa), ya hecho. El mensaje dice qué hacer. |
| 409, 422 | url_required, invalid_url, events_required, already_exists, too_many_webhooks | Webhooks: dirección ausente o rechazada (solo https público), ningún evento conocido, dirección ya suscrita, más de 20 webhooks |
| 429 | rate_limited | Más de 120 llamadas en el minuto: vuelve a intentarlo un poco más tarde |
| 500, 503 | server_error, not_configured | Problema por nuestra parte: vuelve a intentarlo en un momento |
Límites y seguridad
- Una clave da acceso a los datos de tu empresa: guárdala como una contraseña. Úsala desde un servidor o una herramienta de automatización, nunca en una página web ni en una app pública.
- Una clave solo ve su empresa. Nunca da acceso a los códigos de acceso, al Wi-Fi ni a los medios de pago; las fianzas solo se liberan o se cobran mediante las acciones previstas, que quedan registradas.
- Los datos de tus huéspedes, propietarios y miembros del equipo siguen bajo tu responsabilidad: conecta solo programas de confianza, y revoca una clave en cuanto deje de usarse.
- 120 llamadas por minuto y por clave, 20 claves activas como máximo por empresa.
- Las direcciones de la versión 1 no cambiarán. Las novedades llegarán en forma de nuevos campos o de nuevas direcciones.
Si pides ayuda, indica el nombre de la clave utilizada, nunca la clave en sí.