Create a Booking
The book endpoint creates a hotel reservation. Always quote the option immediately before booking to ensure accurate pricing and availability.
Endpoint
POST /connect/hotels/v1/booking
Request
Request Body Structure
The request body contains input and settings:
| Parameter | Type | Description |
|---|---|---|
input | object | Booking input data (required) |
settings | object | Request settings (required) |
Booking Input
| Parameter | Type | Description |
|---|---|---|
optionRefId | string | Option reference ID from prebooking quote (required) |
holder | object | Booking holder (main guest) information (required) |
rooms | array | Room configurations with guest details (required) |
paymentCard | object | Payment card information (if required) |
clientReference | string | Your internal booking reference |
remarks | array | Booking remarks |
priceDelta | number | Price difference tolerance |
additionalData | object | Additional parameters (optional) |
Additional Data Parameters
| Parameter | Type | Description |
|---|---|---|
skipMarkup | string | When "true", skip margin calculation. Suggested price equals net price. |
Example Request
{
"input": {
"optionRefId": "OPT-123456789",
"holder": {
"name": "John",
"surname": "Doe",
"title": "MR"
},
"rooms": [
{
"occupancyRefId": 1,
"paxes": [
{
"name": "John",
"surname": "Doe",
"age": 35
},
{
"name": "Jane",
"surname": "Doe",
"age": 33
}
]
}
],
"paymentCard": {
"type": "VI",
"number": "4111111111111111",
"expire": {
"month": 12,
"year": 2027
},
"holder": {
"name": "John",
"surname": "Doe",
"contactInfo": {
"email": "john.doe@example.com",
"phone": {
"countryCode": "+34",
"number": "600123456"
}
}
}
},
"clientReference": "BOOKING-2025-001",
"remarks": [
{
"type": "GENERAL",
"value": "Late check-in requested"
}
]
},
"settings": {
"connectionCodes": ["testb-hbds-1876"],
"requestId": "book-001"
}
}
Response
Success Response
{
"booking": {
"bookingID": "BK-987654321",
"status": "CONFIRMED",
"clientReference": "BOOKING-2025-001",
"hotel": {
"code": "12345",
"name": "Example Hotel Barcelona"
},
"stay": {
"checkIn": "2025-06-15",
"checkOut": "2025-06-17"
},
"rooms": [
{
"description": "Standard Double Room",
"boardCode": "BB",
"confirmationReference": "ROOM-001",
"paxes": [
{
"name": "John",
"surname": "Doe",
"age": 35
},
{
"name": "Jane",
"surname": "Doe",
"age": 33
}
]
}
],
"holder": {
"name": "John",
"surname": "Doe",
"email": "john.doe@example.com",
"phone": "+34600123456"
},
"price": {
"currency": "EUR",
"net": 150.00,
"suggested": 150.00,
"gross": 150.00,
"markupGross": 180.00,
"markupNet": 180.00,
"markupCurrency": "EUR",
"markupBinding": true,
"marginAmount": 30.00,
"marginPercent": 20.0,
"marginType": "PERCENTAGE"
},
"cancelPolicy": {
"refundable": true,
"cancelPenalties": []
},
"remarks": ["Late check-in requested"],
"createdAt": "2025-06-01T10:30:00Z",
"updatedAt": "2025-06-01T10:30:00Z"
},
"warnings": [],
"errors": []
}
On Request Response
Some bookings require provider confirmation:
{
"booking": {
"bookingID": "BK-987654321",
"status": "ON_REQUEST",
"reference": {
"bookingID": "BK-987654321"
},
...
},
"warnings": [
{
"code": "ON_REQUEST",
"description": "Booking requires provider confirmation"
}
]
}
Key Fields
Booking Status
| Status | Description |
|---|---|
CONFIRMED | Booking confirmed by provider |
PENDING | Booking request submitted, awaiting confirmation |
ON_REQUEST | Provider needs to manually confirm |
FAILED | Booking could not be completed |
Booking References
Store these references for later operations:
bookingID- Bundleport booking ID (use for retrieve, cancel)clientReference- Your internal referenceclientReference- Your internal booking reference (if provided)
Holder Information
The holder is the main guest and booking contact:
- Required: name, surname, email
- Optional: phone, nationality
- Used for: booking confirmation, hotel communication
Guest Information (Paxes)
For each room, provide guest details:
- Adults: name, surname, age (optional)
- Children: name, surname, age (required)
- Type: "ADULT" or "CHILD"
Payment Card
Required for some providers. Include:
- Type: Card type (VI, MC, AX, etc.)
- Number: Card number
- Expire: Expiration month and year
- Holder: Cardholder name
Best Practices
1. Always Quote Before Booking
// ✅ Good - Quote then book
const quote = await quoteOption(optionRefId);
if (quote.errors?.length > 0) {
throw new Error('Option no longer available');
}
const booking = await bookOption(optionRefId, travellerData);
// ❌ Bad - Book without quoting
const booking = await bookOption(optionRefId, travellerData);
// May fail if price changed or option expired
2. Store All References
const booking = await bookOption(optionRefId, travellerData);
// Store all references
await saveBooking({
bundleportId: booking.booking.bookingID,
clientReference: booking.booking.clientReference,
status: booking.booking.status,
});
3. Handle On Request Bookings
const booking = await bookOption(optionRefId, travellerData);
if (booking.booking.status === 'ON_REQUEST') {
// Inform user that confirmation is pending
await notifyUser({
message: 'Your booking is being confirmed. You will receive an email when confirmed.',
bookingId: booking.booking.bookingID,
});
// Set up webhook or polling to check status
await monitorBookingStatus(booking.booking.bookingID);
}
4. Validate Guest Information
function validateGuests(rooms, occupancies) {
for (let i = 0; i < rooms.length; i++) {
const room = rooms[i];
const occupancy = occupancies[i];
// Check total guests match
const totalGuests = room.paxes.length;
const expectedTotal = occupancy.adults + (occupancy.children || 0);
if (totalGuests !== expectedTotal) {
throw new Error(`Room ${i + 1}: Expected ${expectedTotal} guests, got ${totalGuests}`);
}
// Check children ages
const children = room.paxes.filter(p => p.type === 'CHILD' || p.age < 18);
if (children.length !== (occupancy.children || 0)) {
throw new Error(`Room ${i + 1}: Children count mismatch`);
}
}
}
Code Examples
- cURL
- JavaScript
- Python
curl -X POST https://api.bundleport.com/connect/hotels/v1/booking \
-H "Authorization: ApiKey YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"input": {
"optionRefId": "OPT-123456789",
"holder": {
"name": "John",
"surname": "Doe",
"title": "MR"
},
"rooms": [
{
"occupancyRefId": 1,
"paxes": [
{ "name": "John", "surname": "Doe", "age": 35 },
{ "name": "Jane", "surname": "Doe", "age": 33 }
]
}
]
},
"settings": {
"connectionCodes": ["testb-hbds-1876"]
}
}'
async function createBooking(optionRefId, travellerData) {
// Quote first
const quote = await quoteOption(optionRefId);
// Book
const response = await fetch('https://api.bundleport.com/connect/hotels/v1/booking', {
method: 'POST',
headers: {
'Authorization': 'ApiKey YOUR_API_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({
input: {
optionRefId,
holder: travellerData.holder,
rooms: travellerData.rooms,
paymentCard: travellerData.paymentCard,
clientReference: generateClientReference(),
},
settings: {
connectionCodes: ['testb-hbds-1876'],
},
}),
});
const booking = await response.json();
if (booking.errors?.length > 0) {
throw new Error(booking.errors[0].message);
}
return booking.booking;
}
import requests
def create_booking(option_ref_id, traveller_data):
# Quote first
quote = quote_option(option_ref_id)
# Book
url = "https://api.bundleport.com/connect/hotels/v1/booking"
headers = {
"Authorization": "ApiKey YOUR_API_KEY",
"Content-Type": "application/json"
}
payload = {
"input": {
"optionRefId": option_ref_id,
"holder": traveller_data["holder"],
"rooms": traveller_data["rooms"],
"paymentCard": traveller_data.get("paymentCard"),
"clientReference": generate_client_reference(),
},
"settings": {
"connectionCodes": ["testb-hbds-1876"]
}
}
response = requests.post(url, json=payload, headers=headers)
booking = response.json()
if booking.get("errors"):
raise Exception(booking["errors"][0]["message"])
return booking["booking"]
Next Steps
- Retrieve Booking - Get booking details
- List Bookings - Query bookings
- Cancel Booking - Cancel a reservation