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
- Resolve Location — Convert destination to Booking.com city ID
- Search Properties — Fetch matching accommodations
- Get Details — Enrich with photos, amenities, descriptions
- 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
Property Search
GET /json/accommodations
Parameters:
city_ids— Booking.com city identifiercheckin/checkout— Date rangeguest_qty/room_qty— Occupancy requirementsprice_min/price_max— Budget rangefilter_by_hotel_facilities— Amenity requirements
Property Details
GET /json/accommodationDetails
Parameters:
hotel_ids— Comma-separated property IDsextras— 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"},
}
Related Documentation
- Accommodation Overview — System overview
- Sabre Integration — Alternative provider