Skip to main content

Booking.com Integration

Booking.com is the primary accommodation search provider, offering extensive property coverage and real-time availability.

Client Implementation

class BookingDotComClient:
"""Client for Booking.com Connectivity API."""

def __init__(self, api_key: str, affiliate_id: str) -> None:
self.api_key = api_key
self.affiliate_id = affiliate_id
self.base_url = "https://distribution-xml.booking.com/2.0"

async def search_properties(
self,
filters: SearchAccommodationsFilters,
) -> list[BookingProperty]:
"""Search for properties matching filters."""
response = await self._make_request(
"GET",
"/json/accommodations",
params={
"city_ids": await self._resolve_city_id(filters.destination),
"checkin": filters.checkin_date.isoformat(),
"checkout": filters.checkout_date.isoformat(),
"guest_qty": filters.guests,
"room_qty": filters.rooms,
"price_min": filters.min_price,
"price_max": filters.max_price,
},
)
return [BookingProperty(**p) for p in response["result"]]

Search Workflow

  1. Resolve Location — Convert destination to Booking.com city ID
  2. Search Properties — Fetch matching accommodations
  3. Get Details — Enrich with photos, amenities, descriptions
  4. Get Availability — Fetch real-time room availability
async def search_accommodations(
client: BookingDotComClient,
filters: SearchAccommodationsFilters,
) -> list[Accommodation]:
# 1. Search for properties
properties = await client.search_properties(filters)

# 2. Get detailed information in batches
property_ids = [p.hotel_id for p in properties]
details = await client.get_property_details(property_ids)

# 3. Map to domain entities
return [_map_to_accommodation(p, details.get(p.hotel_id)) for p in properties]

API Endpoints

GET /json/accommodations

Parameters:

  • city_ids — Booking.com city identifier
  • checkin / checkout — Date range
  • guest_qty / room_qty — Occupancy requirements
  • price_min / price_max — Budget range
  • filter_by_hotel_facilities — Amenity requirements

Property Details

GET /json/accommodationDetails

Parameters:

  • hotel_ids — Comma-separated property IDs
  • extras — Additional data (photos, descriptions, facilities)

Room Availability

GET /json/blockAvailability

Returns real-time room types, prices, and cancellation policies.

Data Mapping

def _map_to_accommodation(
property: BookingProperty,
details: BookingPropertyDetails | None,
) -> Accommodation:
"""Map Booking.com property to domain entity."""
amenities = []
if details:
amenities = [
Amenity(name=f.facility_name, category=f.facilitytype_name)
for f in details.facilities
]

return Accommodation(
external_id=f"booking:{property.hotel_id}",
name=property.hotel_name,
address=property.address,
city=property.city,
country_code=property.countrycode,
latitude=property.location.latitude,
longitude=property.location.longitude,
star_rating=property.class_,
guest_rating=property.review_score / 2, # Convert 1-10 to 1-5
chain=property.chain_name,
distance_km=property.distance_to_cc, # Distance to city center
amenities=amenities,
)

Amenity Extraction

Booking.com provides facilities in categories. We extract boolean features:

AMENITY_MAPPING = {
"gym": ["gym", "fitness", "fitness centre", "fitness room"],
"wifi": ["wifi", "free wifi", "internet", "wireless internet"],
"breakfast": ["breakfast", "breakfast included", "continental breakfast"],
"parking": ["parking", "free parking", "private parking"],
"restaurant": ["restaurant", "on-site restaurant"],
"bar": ["bar", "lounge", "bar/lounge"],
"pool": ["pool", "swimming pool", "indoor pool", "outdoor pool"],
"spa": ["spa", "wellness", "sauna"],
}

def extract_amenity_features(facilities: list[Facility]) -> dict[str, bool]:
"""Extract boolean amenity features from facilities list."""
facility_names = {f.facility_name.lower() for f in facilities}

features = {}
for feature_name, keywords in AMENITY_MAPPING.items():
features[feature_name] = any(
keyword in name for keyword in keywords for name in facility_names
)
return features

Rate Limiting

Booking.com enforces rate limits. The client handles this gracefully:

class BookingDotComClient:
def __init__(self, ...):
self.rate_limiter = RateLimiter(max_requests=100, window_seconds=60)

async def _make_request(self, method: str, endpoint: str, **kwargs) -> dict:
async with self.rate_limiter:
response = await self.http_client.request(
method,
f"{self.base_url}{endpoint}",
headers={"Authorization": f"Basic {self._auth_header}"},
**kwargs,
)

if response.status_code == 429:
retry_after = int(response.headers.get("Retry-After", 60))
await asyncio.sleep(retry_after)
return await self._make_request(method, endpoint, **kwargs)

response.raise_for_status()
return response.json()

Configuration

# Environment variables
BOOKING_COM_API_URL=https://distribution-xml.booking.com/2.0
BOOKING_COM_API_KEY=your-api-key
BOOKING_COM_AFFILIATE_ID=your-affiliate-id

MCP Resource

Available filters are exposed as an MCP resource:

@mcp.resource(
uri="data://search-accommodations-filters",
description="Get the list of filters for searching accommodations",
mime_type="application/json",
)
async def get_search_accommodations_filters() -> dict[str, Any]:
return {
"destination": {"type": "string", "required": True},
"checkin_date": {"type": "date", "required": True},
"checkout_date": {"type": "date", "required": True},
"guests": {"type": "integer", "default": 1},
"rooms": {"type": "integer", "default": 1},
"min_price": {"type": "number", "required": False},
"max_price": {"type": "number", "required": False},
"star_rating": {"type": "array", "items": "integer"},
"amenities": {"type": "array", "items": "string"},
}