Tutorial de arquitectura para un comparador de hoteles y Airbnb: resolver identidad, tarifas multi-OTA en vivo, normalizar como-por-como, caché y créditos, paridad como señal.
Un comparador de precios de hoteles con API recibe una petición de estancia — hotel, entrada, salida, ocupación —, resuelve la identidad de ese hotel en cada canal, pide el precio en vivo a cada OTA y plataforma de alquiler vacacional, normaliza las respuestas a un producto comparable y las ordena. Veetal Connect API ofrece cada pieza como un endpoint separado: una Account API para resolver identidades, una capa Real Time con tarifas en vivo de Booking.com, Expedia, Hotels.com, Google Hotels y Airbnb, una caché configurable de 0 a 24 h para controlar el gasto en créditos, y un dataset de paridad que puedes añadir como señal.
Esto es un tutorial de arquitectura, no un volcado de código: qué endpoint responde a qué pregunta, dónde se rompen las comparaciones y por dónde se va el dinero.
Qué hace de verdad un comparador de precios de hoteles
La interfaz es la parte fácil. Lo difícil es que "el precio de un hotel" no existe como número único: cada canal vende varios productos para la misma habitación (solo alojamiento o con desayuno, flexible o no reembolsable, escritorio o móvil, público o para miembros), en su moneda y con sus reglas de ocupación. Un flujo de metabuscador hotelero vía API tiene que reducir eso a algo que el usuario pueda ordenar.
El pipeline, en texto:
[1] Resolver identidad nombre / URL → slug · bookingId · expedia-id · entidad GHA · listingId de Airbnb
│
[2] Llamadas en paralelo parity (todas las OTAs en Google Hotels) + Booking + Expedia/Hotels.com + Airbnb
│
[3] Normalizar moneda · régimen · cancelación · ocupación · total vs por noche
│
[4] Caché y presupuesto caché 0–24 h · contador de créditos · búsqueda por destino en vez de hotel a hotel
│
[5] Enriquecer y ordenar parity score · producto comparable más barato · enlace profundo
Paso 0: decidir de dónde salen los precios
Los equipos que montan su primer comparador suelen plantearse extraer ellos mismos los precios de las páginas de las OTAs. Funciona para una demo y falla en producción, por razones puramente técnicas.
| Criterio | Extracción propia de páginas de OTAs | API de datos hoteleros (Veetal Connect API) |
|---|---|---|
| Salida | HTML crudo que cambia con cada rediseño | JSON estable con campos tipados (price_per_night, meal_plan, cancellation) |
| Cobertura multi-OTA | Un parser por OTA, cada uno con su mantenimiento | Un esquema común para Booking, Expedia, Hotels.com, Google Hotels y Airbnb |
| Fiabilidad | Se rompe en silencio al cambiar la maqueta; fricción anti-bot a volumen | Infraestructura de acceso gestionada; tú consumes el resultado |
| Modelo de coste | Horas de ingeniería, infraestructura, reintentos | Créditos por llamada; las repeticiones cacheadas no cuestan más |
Cinco OTAs son cinco parsers y cinco rediseños que perseguir; una API traslada ese trabajo a un proveedor cuyo oficio es mantener el esquema estable. La comparación completa está en API hotelera vs web scraping, y qué significa "en vivo" en este sector, en precios de hotel en tiempo real vía API.
Paso 1: resolver la identidad del hotel en cada canal
Un comparador muere en el primer paso si no sabe si "Hotel Vincci Marítimo" en una web y "Vincci Maritimo Barcelona" en otra son el mismo producto. Veetal Connect API lo resuelve con dos patrones de identidad:
- Alojamiento registrado (
slug). Das de alta el hotel una vez en la Account API (POST /v2/account/accommodation) y obtienes unslugcomovincci-mae. Desde entonces, todos los endpoints Feed y Real Time aceptanreference_type=accommodationmás ese slug. Es el patrón adecuado para un conjunto conocido de hoteles: los de tus clientes y sus compsets. - Referencia por entidad de canal. Para un hotel cualquiera que escribe el usuario, lo referencias por su identificador en el canal:
booking-entity(bookingId+dest_txt+dest_id+country),expedia-id,hotelscom-id,google-hotel-ads-entityo ellistingIdnumérico de Airbnb. Varios endpoints autocrean el alojamiento en la primera llamada, así que la segunda ya tiene slug.
Los ayudantes de resolución:
GET /v2/real-time/booking/search/hotel/{name}— localiza un hotel en Booking por nombre y devuelve sus campos de entidad.GET /v2/real-time/expedia/search/{type}yGET /v2/real-time/hotelscom/search/{type}— lo mismo en Expedia y Hotels.com.GET /v2/real-time/airbnb/search?query=...— sugerencias de destino en Airbnb; el id del anuncio sale de la URL de la habitación o de una llamada de tarifas por ubicación.GET /v2/real-time/search/cities?query=...— la búsqueda de catálogo (regiones, países, ciudades, aeropuertos, monedas). 0 créditos, así que úsala sin miedo para autocompletar y para ids geográficos.
Persiste el mapa resuelto (slug → ids por canal): la identidad cuesta créditos una vez, no en cada búsqueda.
Paso 2: pedir el precio en vivo a todos los canales
La capa Real Time de Veetal ofrece dos granularidades y un buen comparador usa las dos.
Nivel hotel, todas las OTAs en una llamada. El endpoint de parity devuelve una tarifa por OTA tal y como aparece en Google Hotels para la estancia — Booking, Expedia, Hotels.com, la web oficial y cualquier otra que venda esa noche —, cada una con rate, link, is_official_website y extras de cancelación, más total_otas_found:
GET /v2/real-time/accommodation/vincci-mae/parity/2026-11-06/2026-11-08/2?currency=eur
Una llamada, 4–14 segundos, y ya tienes la tabla de cabecera de cualquier comparador. Es el endpoint que hay detrás de la fuente Google Hotels y del dataset de disparidad hotelera.
Nivel habitación, por canal. Cuando el usuario quiere saber qué habitación y qué condiciones producen ese precio:
| Canal | Endpoint | Qué devuelve | Latencia |
|---|---|---|---|
| Booking.com | GET /v2/real-time/accommodation/{slug}/rate/booking/{checkin}/{checkout}/{adults} | Habitaciones con price_per_night, price_total, capacity, meal_plan, cancellation, ofertas genius/móvil | 5–20 s |
| Expedia | GET /v2/real-time/{reference_type}/{identifier}/rate/expedia/{checkin}/{checkout}/{adults} | Tipos de habitación, room_max_occupancy, régimen, configuración de camas | 15–30 s |
| Hotels.com | GET /v2/real-time/{reference_type}/{identifier}/rate/hotelscom/{checkin}/{checkout}/{adults} | Misma forma que Expedia | 15–30 s |
| Airbnb | GET /v2/real-time/airbnb/listing/{listingId}/rate/{checkin}/{checkout}/{adults} | total, originalTotal, desglose por partidas, planes con flag refundable | 5–15 s |
Lanza las llamadas por canal en paralelo, con un timeout de unos 45 s por llamada, y pinta los resultados según llegan. Trata "sin tarifa" como respuesta de primera clase: el endpoint de Booking devuelve un reason cuando el hotel está completo o no cabe el grupo. La fuente Booking.com es la única que devuelve un destino entero en una llamada; la fuente Airbnb cubre la oferta de alquiler vacacional que compite con los hoteles y nunca aparece en los feeds hoteleros.
Paso 3: normalizar para comparar como-por-como
Aquí es donde la mayoría de comparadores multi-OTA fallan sin querer. Una habitación a 189 solo alojamiento y flexible no es más barata que una a 205 no reembolsable con desayuno: son productos distintos. Normaliza antes de ordenar:
- Moneda. Pide la misma moneda en todas partes (
currency=eurousden parity; ISO-4217 en Booking y Airbnb). - Régimen. Mapea cada canal a un único enum: solo alojamiento, desayuno, media pensión, pensión completa, todo incluido. Booking expone booleanos bajo
meal_plan; Expedia/Hotels.com usan códigos (alo,ad,mp,pc,ti); Airbnb es siempre solo alojamiento. - Cancelación. Reduce a
flexible/no_reembolsablemás la fecha límite de cancelación gratuita (free_cancellation_daysen Booking y parity,refundablepor plan en Airbnb). - Ocupación. Compara habitaciones donde quepa el grupo:
capacity/can_fit_all_guestsen Booking,room_max_occupancyen Expedia y Hotels.com. Airbnb pone precio a la unidad entera, así que guarda explícitamente el "duerme N". - Total vs por noche. Guarda los dos. El
totalde Airbnb incluye tasas que un precio por noche esconde. - Audiencia. Marca las tarifas para miembros, solo móvil y promocionales (
is_genius,is_mobile_offer,has_offer): precios reales, pero no reservables por todo el mundo.
Después ordena dentro de cada cubo de producto (desayuno · flexible · 2 adultos), nunca entre cubos. La receta rate shopping comparable implementa exactamente esa agrupación sobre la capa Feed; su ejemplo muestra un hotel que parecía un 28 % más barato que un competidor hasta que el informe se dio cuenta de que el competidor no vendía tarifa flexible. Ese hallazgo es el producto de un comparador; un único número "más barato" lo esconde.
Paso 4: controlar el coste con la caché y el contador de créditos
Un comparador es un multiplicador de llamadas en vivo: cinco canales por búsqueda, muchas búsquedas por usuario. Tres palancas lo mantienen bajo control.
La caché. Las respuestas Real Time se pueden cachear por API desde el dashboard, de 0 a 24 horas. Dentro de la ventana, una petición repetida devuelve el payload cacheado sin coste extra. Ajusta la ventana por superficie:
- Resultados de búsqueda o listado de destino: 6–24 h.
- Ficha de hotel: 1–3 h.
- Botón "comprobar precio antes de reservar":
?no_cache=truesolo en esa petición. El parámetro es global: fresco solo donde la frescura vende.
El contador de créditos. GET /v2/account/customer-info devuelve saldo y consumo sin coste. Conéctalo a tus métricas y alerta por ritmo de gasto; la receta controlar tu consumo es un script pequeño que lo hace. Planes y paquetes de créditos, en la página de precios.
Búsqueda por destino en vez de hotel a hotel. Para "hoteles en Lisboa en estas fechas", no lances una llamada por hotel. GET /v2/real-time/location-search/{location_search_id}/booking/{target_date} ejecuta una búsqueda de destino y devuelve todos los alojamientos encontrados con su precio. En la capa Feed el mismo dataset es muchísimo más barato: la receta controlar el ranking de tu plaza lee 192 hoteles de un destino por 0,32 créditos. Usa la lectura Feed para el listado — el dataset de tarifas de hoteles es la cara Feed de los datos que pides en vivo en el paso 2, con histórico incorporado — y reserva Real Time para los hoteles que el usuario abre. Regla práctica: Feed para lo recurrente y configurado, Real Time para lo puntual y arbitrario.
Paso 5: añadir la paridad como señal, no solo como precio
Un comparador que solo enseña precios es una commodity; uno que los explica, un producto. El endpoint de parity de la capa Feed devuelve un parity score pre-procesado de un hotel registrado frente a su compset:
GET /v2/feed/accommodation/vincci-mae/parity?from_date=2026-11-06&to_date=2026-11-13&adults=2&device=desktop
Úsalo para señales que la parrilla cruda no da: "la web oficial está un 4 % por debajo de la OTA más barata en 6 de las próximas 7 noches". Para un producto de metabúsqueda es un sello de confianza; para una agencia de marketing hotelero, el argumento de la reserva directa. Los casos límite están en qué es la paridad de tarifas hoteleras.
La superficie de comparación es donde se decide: el análisis de Mirai sobre canales directos hoteleros encontró que la cuota de Google Hotels en las reservas por metabuscador pasó de cerca del 70 % en 2019 a más del 85 % en 2022, y que la metabúsqueda aportaba en torno al 13 % de los ingresos directos (Mirai, 2023). Tener los datos que hay detrás de esa superficie es lo que hace defendible la herramienta.
Errores típicos al montar un comparador de precios de hoteles
- Ordenar tarifas no comparables. El más barato por canal mezclando regímenes y políticas de cancelación. Solución: normalizar primero y ordenar dentro del cubo de producto.
- Ignorar la caché. Cada vista de página dispara una llamada en vivo. Solución: 6–24 h en listados,
no_cache=truesolo en el paso previo a reservar. - Llamar hotel a hotel cuando existe la búsqueda por destino. Solución: una búsqueda de ubicación y luego el detalle por hotel bajo demanda.
- Mezclar ocupaciones y bases. Una habitación "para 2" junto a una unidad "para 4", o por noche junto a totales. Solución: llevar
sleepsy las dos bases de precio en cada registro. - Tratar los timeouts como precio cero. Solución: distinguir
no_rate,timeoutysold_outen el esquema y en la interfaz.
Un escenario real: una app de comparación para escapadas urbanas
Una startup de viajes construye una app de comparación para escapadas en España, Portugal e Italia: ciudad y fechas, hoteles y apartamentos juntos, precio canal por canal al abrir cada alojamiento.
- Listado. Una lectura Feed de la búsqueda de ubicación de Booking del destino más una llamada de tarifas por ubicación de Airbnb cacheada 12 h: una lista mixta con un total comparable para la estancia.
- Ficha. La llamada de parity para hoteles y la tarifa del anuncio de Airbnb para apartamentos, con caché de 2 h. Un botón "comprobar precio en vivo" dispara la llamada de Booking a nivel habitación con
no_cache=true. - Señales y presupuesto. Parity score de los hoteles registrados con compset, mostrado como sello "mejor precio directo"; customer-info consultado cada 10 minutos con alerta al 80 % del plan mensual de créditos.
La receta rate shopper en vivo es la versión mínima de esa ficha: un hotel, una estancia, la parrilla de habitaciones de Booking en segundos. Empieza ahí, añade la llamada de parity y tienes el núcleo de la herramienta.
Preguntas frecuentes
¿Qué es una API de comparación de precios de hoteles? Una API que devuelve el precio de una estancia en varios canales de venta en un único formato estructurado, para que un desarrollador pueda compararlos y ordenarlos sin extraer páginas. Veetal Connect API lo ofrece con su capa Real Time (tarifas en vivo de Booking.com, Expedia, Hotels.com, Google Hotels y Airbnb) y su capa Feed (tarifas y paridad pre-procesadas para hoteles registrados).
¿Puedo comparar hoteles con anuncios de Airbnb en la misma herramienta? Sí. Los endpoints de Airbnb de Veetal devuelven el total en vivo, los planes de tarifa y la reembolsabilidad de un anuncio, o los anuncios con precio de un destino entero. Normaliza por precio total de la estancia y por plazas, porque Airbnb pone precio a la unidad y no a una habitación.
¿Cómo de frescos son los precios?
Las llamadas Real Time obtienen el precio en el momento de la petición, normalmente en 4–30 segundos según el canal. Con la caché activa (0–24 h, por API), las peticiones repetidas dentro de la ventana devuelven la respuesta almacenada; no_cache=true fuerza una consulta fresca.
¿Cuántos créditos cuesta una comparación?
Cada llamada Real Time consume créditos que varían por endpoint; las repeticiones cacheadas no cuestan más y los endpoints de Account son gratuitos. La prueba gratuita incluye 1.000 créditos, y GET /v2/account/customer-info informa de tu saldo para presupuestar por búsqueda.
¿Uso Feed o Real Time para un comparador? Las dos. Feed para lo recurrente y configurado — listados de destino, hoteles registrados, compsets — porque las lecturas son baratas y el histórico se acumula. Real Time para hoteles arbitrarios y el momento de la decisión, donde la frescura vale un crédito.
Empieza a construir
Todo esto corre en el plan gratuito: resuelve un hotel, llama a parity y a la parrilla de habitaciones de Booking, y tendrás tu primera tabla comparativa en minutos. La prueba incluye 1.000 créditos sin tarjeta — empieza con Veetal Connect API.