Skip to main content

Java SDK

The Bundleport Java SDK provides a type-safe client for the Connect Hotels REST API with support for both reactive (Spring WebFlux) and blocking operations.

Install

Gradle

dependencies {
implementation("com.bundleport:connect-hotels-sdk:<version>")
}

Maven

<dependency>
<groupId>com.bundleport</groupId>
<artifactId>connect-hotels-sdk</artifactId>
<version>${bundleport.version}</version>
</dependency>

Initialize the Client

Blocking Client

import com.bundleport.client.BundleportClient;
import com.bundleport.client.ClientConfig;
import java.time.Duration;

ClientConfig config = ClientConfig.builder()
.apiKey("YOUR_API_KEY_HERE")
.baseUrl("https://api.bundleport.com") // Optional
.timeout(Duration.ofSeconds(30)) // Optional
.build();

BundleportClient client = new BundleportClient(config);

Reactive Client (Spring WebFlux)

import com.bundleport.client.reactive.ReactiveBundleportClient;
import org.springframework.web.reactive.function.client.WebClient;

WebClient webClient = WebClient.builder()
.baseUrl("https://api.bundleport.com")
.build();

ReactiveBundleportClient client = new ReactiveBundleportClient(
webClient,
"YOUR_API_KEY_HERE"
);

Booking Operations

Search for Hotels (Availability)

SearchRequest request = SearchRequest.builder()
.criteria(SearchCriteria.builder()
.checkIn("2025-06-15T00:00:00Z")
.checkOut("2025-06-17T00:00:00Z")
.occupancies(List.of(
Occupancy.builder()
.paxes(List.of(
Pax.builder().name("John").surname("Doe").age(35).build(),
Pax.builder().name("Jane").surname("Doe").age(33).build(),
Pax.builder().name("Child").surname("Doe").age(8).build()
))
.build()
))
.hotels(List.of("12345", "67890")) // Optional
.currency("EUR")
.language("en")
.nationality("US")
.build())
.settings(Settings.builder()
.connectionCodes(List.of("testb-hbds-1876"))
.timeout(30000)
.build())
.build();

SearchResponse result = client.hotels().searchAvailability(request);
System.out.println("Found " + result.getOptions().size() + " options");

Get Prebooking Quote

QuoteRequest quoteRequest = QuoteRequest.builder()
.criteria(QuoteCriteria.builder()
.optionRefId(result.getOptions().get(0).getOptionRefId())
.build())
.settings(Settings.builder()
.connectionCodes(List.of("testb-hbds-1876"))
.build())
.build();

QuoteResponse quoteResult = client.hotels().getPrebooking(quoteRequest);

// Check for price changes
boolean priceChanged = quoteResult.getWarnings().stream()
.anyMatch(w -> "PRICE_CHANGED".equals(w.getCode()));
if (priceChanged) {
System.out.println("Price has changed: " + quoteResult.getOptionQuote().getPrice());
}

Create a Booking

BookRequest bookRequest = BookRequest.builder()
.input(BookInput.builder()
.optionRefId(quoteResult.getOptionQuote().getOptionRefId())
.holder(Holder.builder()
.name("John")
.surname("Doe")
.title("MR")
.build())
.rooms(List.of(
BookRoom.builder()
.occupancyRefId(1)
.paxes(List.of(
Pax.builder().name("John").surname("Doe").age(35).build(),
Pax.builder().name("Jane").surname("Doe").age(33).build()
))
.build()
))
.paymentCard(PaymentCard.builder()
.type("VI")
.number("4111111111111111")
.expire(CardExpire.builder().month(12).year(2027).build())
.holder(CardHolder.builder()
.name("John")
.surname("Doe")
.contactInfo(ContactInfo.builder()
.email("john.doe@example.com")
.phone(Phone.builder()
.countryCode("+34")
.number("600123456")
.build())
.build())
.build())
.build())
.clientReference("BOOKING-2025-001")
.build())
.settings(Settings.builder()
.connectionCodes(List.of("testb-hbds-1876"))
.build())
.build();

BookResponse booking = client.hotels().createBooking(bookRequest);
System.out.println("Booking confirmed: " + booking.getBooking().getBookingID());

Reactive Usage

import reactor.core.publisher.Mono;

Mono<SearchResponse> searchMono = reactiveClient.hotels().searchAvailability(request);

Mono<QuoteResponse> quoteMono = searchMono.flatMap(result ->
reactiveClient.hotels().getPrebooking(QuoteRequest.builder()
.criteria(QuoteCriteria.builder()
.optionRefId(result.getOptions().get(0).getOptionRefId())
.build())
.build())
);

quoteMono.subscribe(
quote -> System.out.println("Quote received: " + quote.getOptionQuote().getPrice()),
error -> System.err.println("Error: " + error.getMessage())
);

Retrieve Booking Details

BookingDetailRequest detailRequest = BookingDetailRequest.builder()
.criteria(BookingDetailCriteria.builder()
.bookingID("BK-987654321")
.build())
.settings(Settings.builder()
.connectionCodes(List.of("testb-hbds-1876"))
.build())
.build();

BookingDetailResponse bookingDetails = client.hotels().getBookingDetail(detailRequest);
System.out.println("Booking status: " + bookingDetails.getBooking().getStatus());

List Bookings

BookingListRequest listRequest = BookingListRequest.builder()
.criteria(BookingListCriteria.builder()
.typeSearch("BOOKING_LIST_CRITERIA_TYPE_DATES")
.dates(BookingListDates.builder()
.dateType("BOOKING_LIST_CRITERIA_DATE_TYPE_ARRIVAL")
.start("2025-06-01T00:00:00Z")
.end("2025-06-30T00:00:00Z")
.build())
// Or search by booking ID:
// .typeSearch("BOOKING_LIST_CRITERIA_TYPE_BOOKING_ID")
// .bookingID("BK-987654321")
.build())
.settings(Settings.builder()
.connectionCodes(List.of("testb-hbds-1876"))
.build())
.build();

BookingListResponse bookings = client.hotels().listBookings(listRequest);
System.out.println("Found " + bookings.getBookings().size() + " bookings");

Cancel Booking

CancelRequest cancelRequest = CancelRequest.builder()
.input(CancelInput.builder()
.bookingID("BK-987654321")
.build())
.settings(Settings.builder()
.connectionCodes(List.of("testb-hbds-1876"))
.build())
.build();

CancelResponse cancelResult = client.hotels().cancel(cancelRequest);
System.out.println("Cancellation status: " + cancelResult.getCancel().getStatus());
if (!cancelResult.getCancel().getCancelPenalties().isEmpty()) {
for (CancelPenalty penalty : cancelResult.getCancel().getCancelPenalties()) {
System.out.println("Cancellation penalty: " + penalty.getValue() + " " + penalty.getCurrency());
}
}

Content Operations

Get Hotels

HotelsRequest hotelsRequest = HotelsRequest.builder()
.query(HotelListQuery.builder()
.destinationCodes(List.of("BCN"))
.maxSize(100)
.build())
.build();

HotelsResponse hotels = client.content().getHotels(hotelsRequest);
System.out.println("Found " + hotels.getHotels().getHotels().size() + " hotels");

Error Handling

import com.bundleport.exceptions.BundleportException;
import com.bundleport.exceptions.UnauthorizedException;
import com.bundleport.exceptions.RateLimitException;

try {
SearchResponse result = client.hotels().searchAvailability(request);
} catch (UnauthorizedException e) {
System.err.println("Invalid API key");
} catch (RateLimitException e) {
System.err.println("Rate limit exceeded, retry after: " + e.getRetryAfter() + " seconds");
} catch (BundleportException e) {
System.err.println("API error: " + e.getMessage());
}

Next Steps