Search for Hotels
The search endpoint allows you to find available hotels matching your criteria. It queries multiple suppliers in parallel and returns normalized results.
Endpoint
POST /hotels/v1/search
Request
Required Parameters
| Parameter | Type | Description |
|---|---|---|
stay | object | Check-in and check-out dates |
destination | object | Destination (code or coordinates) |
occupancies | array | Guest configuration per room |
Optional Parameters
| Parameter | Type | Description |
|---|---|---|
filters | object | Search filters (currency, price range, etc.) |
settings | object | Request settings (accessIds, timeout, etc.) |
Example Request
{
"stay": {
"checkIn": "2025-06-15",
"checkOut": "2025-06-17"
},
"destination": {
"code": "BCN"
},
"occupancies": [
{
"adults": 2,
"children": 1,
"childrenAges": [8]
}
],
"filters": {
"currency": "EUR",
"nationality": "ES",
"minPrice": 50,
"maxPrice": 300,
"boardTypes": ["BB", "HB"]
},
"settings": {
"accessIds": ["ACCESS_1", "ACCESS_2"],
"timeout": 30000
}
}
Response
Success Response
{
"options": [
{
"optionRefId": "OPT-123456789",
"hotel": {
"code": "12345",
"name": "Example Hotel Barcelona",
"location": {
"city": "Barcelona",
"country": "ES"
}
},
"rooms": [
{
"description": "Standard Double Room",
"boardCode": "BB",
"price": {
"currency": "EUR",
"net": 150.00,
"suggested": 180.00
},
"cancelPolicy": {
"refundable": true,
"cancelPenalties": []
}
}
],
"price": {
"currency": "EUR",
"net": 150.00,
"suggested": 180.00,
"binding": false
}
}
],
"tracing": {
"status": "OK",
"accessSpans": [
{
"access": "ACCESS_1",
"status": "OK",
"hotelsRequested": 10,
"hotelsReturned": 8
}
]
},
"warnings": []
}
Key Fields
optionRefId
Unique identifier for this option. Use it to:
- Quote the option (recheck pricing)
- Book the option
- Reference in subsequent operations
Important: optionRefId is only valid for a limited time (typically 4-5 minutes). Always quote immediately before booking.
Destination
You can specify destination in multiple ways:
// By code (IATA, city code, etc.)
{ "destination": { "code": "BCN" } }
// By coordinates
{ "destination": { "latitude": 41.3851, "longitude": 2.1734 } }
// By geohash
{ "destination": { "geohash": "sp3e3" } }
Occupancies
Define guest configuration:
{
"occupancies": [
{
"adults": 2,
"children": 0
},
{
"adults": 1,
"children": 2,
"childrenAges": [8, 10]
}
]
}
This example searches for:
- Room 1: 2 adults
- Room 2: 1 adult + 2 children (ages 8 and 10)
Filters
Common filters:
{
"filters": {
"currency": "EUR", // Response currency
"nationality": "ES", // Guest nationality
"minPrice": 50, // Minimum price
"maxPrice": 300, // Maximum price
"boardTypes": ["BB", "HB"], // Filter by board types
"hotelCodes": ["12345"], // Specific hotels
"starRating": [4, 5], // Star rating filter
"amenities": ["WIFI", "POOL"] // Required amenities
}
}
Settings
Request configuration:
{
"settings": {
"accessIds": ["ACCESS_1"], // Which suppliers to query
"timeout": 30000, // Request timeout (ms)
"requestId": "search-001", // Your request ID for tracing
"auditTransactions": false // Include raw supplier responses
}
}
Multi-Supplier Behavior
When multiple suppliers are configured:
- Parallel Queries - All suppliers queried simultaneously
- Deduplication - Same hotel from different suppliers is consolidated
- Ranking - Business rules determine best options
- Partial Results - If one supplier fails, others continue
Partial Failure Example
{
"options": [...], // Results from successful suppliers
"tracing": {
"status": "PARTIAL",
"accessSpans": [
{ "access": "ACCESS_1", "status": "OK", "hotelsReturned": 45 },
{ "access": "ACCESS_2", "status": "OK", "hotelsReturned": 32 },
{ "access": "ACCESS_3", "status": "ERROR", "errorCode": "TIMEOUT" }
]
},
"warnings": [
{ "code": "PARTIAL_RESPONSE", "description": "ACCESS_3 timeout" }
]
}
Best Practices
1. Always Quote Before Booking
optionRefId expires quickly. Always quote immediately before booking:
// ✅ Good
const search = await searchHotels(criteria);
const option = search.options[0];
const quote = await quoteOption(option.optionRefId);
const booking = await bookOption(option.optionRefId, travellerData);
// ❌ Bad - optionRefId may expire
const search = await searchHotels(criteria);
// ... user browses for 10 minutes ...
const booking = await bookOption(option.optionRefId, travellerData); // May fail
2. Use Appropriate Filters
Narrow down results to improve performance:
// ✅ Good - Specific filters
{
"filters": {
"currency": "EUR",
"minPrice": 100,
"maxPrice": 200,
"boardTypes": ["BB"]
}
}
// ❌ Bad - Too broad
{
"filters": {
"currency": "EUR"
// No price or board filters = too many results
}
}
3. Monitor Tracing Data
Use tracing to optimize supplier selection:
const result = await searchHotels(criteria);
result.tracing.accessSpans.forEach(span => {
console.log(`${span.access}: ${span.status}, ${span.hotelsReturned} hotels, ${span.processTime}ms`);
if (span.status === 'ERROR') {
// Log supplier issues
console.error(`Supplier ${span.access} failed: ${span.errorCode}`);
}
});
4. Handle Warnings
Warnings indicate data quality issues but don't prevent success:
if (result.warnings.length > 0) {
result.warnings.forEach(warning => {
if (warning.code === 'UNMAPPED_HOTEL') {
// Hotel exists but content not fully mapped
// Still usable, but may have limited information
}
});
}
Code Examples
- cURL
- JavaScript
- Python
curl -X POST https://api.bundleport.com/hotels/v1/search \
-H "Authorization: ApiKey YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"stay": {
"checkIn": "2025-06-15",
"checkOut": "2025-06-17"
},
"destination": { "code": "BCN" },
"occupancies": [{ "adults": 2 }],
"filters": { "currency": "EUR" }
}'
const response = await fetch('https://api.bundleport.com/hotels/v1/search', {
method: 'POST',
headers: {
'Authorization': 'ApiKey YOUR_API_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({
stay: {
checkIn: '2025-06-15',
checkOut: '2025-06-17',
},
destination: { code: 'BCN' },
occupancies: [{ adults: 2 }],
filters: { currency: 'EUR' },
}),
});
const data = await response.json();
console.log(`Found ${data.options.length} options`);
import requests
url = "https://api.bundleport.com/hotels/v1/search"
headers = {
"Authorization": "ApiKey YOUR_API_KEY",
"Content-Type": "application/json"
}
payload = {
"stay": {
"checkIn": "2025-06-15",
"checkOut": "2025-06-17"
},
"destination": {"code": "BCN"},
"occupancies": [{"adults": 2}],
"filters": {"currency": "EUR"}
}
response = requests.post(url, json=payload, headers=headers)
data = response.json()
print(f"Found {len(data['options'])} options")
Next Steps
- Quote an Option - Revalidate pricing before booking
- Create a Booking - Book the selected option
- Content API - Access hotel catalog data