Cancel a Booking
The cancel endpoint cancels a hotel reservation. Whether a stay is free to cancel or incurs a penalty depends on the supplier policy already attached to the booking—always retrieve the booking (or trust your last cached policy) before you call cancel in customer-facing flows.
Endpoint
POST /connect/hotels/v1/cancel
Request
Request Body Parameters
| Parameter | Type | Description |
|---|---|---|
input.bookingID | string | Bundleport booking ID (required) |
settings.connectionCodes | array | Provider connection codes (required) |
| Parameter | Type | Description |
|---|---|---|
reason | string | Cancellation reason (optional) |
cancelPenalty | object | Penalty handling (optional) |
Example Request
{
"input": {
"bookingID": "BK-987654321"
},
"settings": {
"connectionCodes": ["testb-hbds-1876"]
}
}
Response
Success Response
{
"booking": {
"bookingID": "BK-987654321",
"status": "CANCELLED",
"cancelPenalties": [
{
"value": 75.00,
"currency": "EUR",
"deadline": "2025-06-10T00:00:00Z",
"hoursBefore": 24
}
]
}
}
Free Cancellation
If cancellation is free:
{
"booking": {
"bookingID": "BK-987654321",
"status": "CANCELLED",
"cancelPenalties": []
}
}
Cancellation Policies
Before canceling, check the cancellation policy:
const booking = await getBooking(bookingId);
const cancelPolicy = booking.booking.cancelPolicy;
if (!cancelPolicy.refundable) {
// Non-refundable - full penalty
console.log('Booking is non-refundable');
} else {
// Check if within free cancellation period
const freeCancelDeadline = getFreeCancelDeadline(cancelPolicy.cancelPenalties);
const now = new Date();
if (now < new Date(freeCancelDeadline)) {
console.log('Free cancellation available');
} else {
// Calculate penalty
const penalty = calculatePenalty(cancelPolicy.cancelPenalties, booking.booking.price);
console.log(`Cancellation penalty: ${penalty.amount} ${penalty.currency}`);
}
}
Best Practices
Treat cancel as a committed operation: after a successful response, assume the reservation is gone at Bundleport and at the supplier unless support says otherwise. The snippets below are illustrative—replace getBooking / cancelBookingRequest with your HTTP client.
1. Check cancellation policy first
async function safeCancelBooking(bookingId) {
const booking = await getBooking(bookingId);
const penalty = calculateCancellationPenalty(booking.booking);
if (penalty.amount > 0) {
const confirmed = await confirmCancellation({
bookingId,
penalty,
message: `Cancellation penalty: ${penalty.amount} ${penalty.currency}`,
});
if (!confirmed) {
return { cancelled: false };
}
}
return await cancelBookingRequest(bookingId);
}
2. Handle cancellation response
Map CANCELLED to your PMS or OMS, store returned penalties for finance, and trigger customer comms from your notification layer.
const cancelResult = await cancelBooking(bookingId, reason);
if (cancelResult.booking.status === 'CANCELLED') {
// Process refund if applicable
// Note: Refund information would be in the booking details, not in cancel response
// Update internal records
await updateBookingStatus(bookingId, 'CANCELLED');
// Notify customer
await notifyCustomer({
bookingId,
status: 'CANCELLED',
penalties: cancelResult.booking.cancelPenalties,
});
}
Code Examples
- cURL
- JavaScript
- Python
- Java
- C#
curl -X POST https://api.bundleport.com/connect/hotels/v1/cancel \
-H "Authorization: ApiKey YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"input": {
"bookingID": "BK-987654321"
},
"settings": {
"connectionCodes": ["testb-hbds-1876"]
}
}'
async function cancelBooking(bookingId) {
const response = await fetch(
'https://api.bundleport.com/connect/hotels/v1/cancel',
{
method: 'POST',
headers: {
'Authorization': 'ApiKey YOUR_API_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({
input: {
bookingID: bookingId,
},
settings: {
connectionCodes: ['testb-hbds-1876'],
},
}),
}
);
if (!response.ok) {
const error = await response.json();
throw new Error(error.error?.message || 'Failed to cancel booking');
}
return await response.json();
}
import requests
def cancel_booking(booking_id):
url = "https://api.bundleport.com/connect/hotels/v1/cancel"
headers = {
"Authorization": "ApiKey YOUR_API_KEY",
"Content-Type": "application/json"
}
payload = {
"input": {
"bookingID": booking_id
},
"settings": {
"connectionCodes": ["testb-hbds-1876"]
}
}
response = requests.post(url, json=payload, headers=headers)
if not response.ok:
error = response.json()
raise Exception(error.get("error", {}).get("message", "Failed to cancel booking"))
return response.json()
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
var body = """
{
"input": { "bookingID": "BK-987654321" },
"settings": { "connectionCodes": ["testb-hbds-1876"] }
}
""";
var request = HttpRequest.newBuilder()
.uri(URI.create("https://api.bundleport.com/connect/hotels/v1/cancel"))
.header("Authorization", "ApiKey YOUR_API_KEY")
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(body))
.build();
var client = HttpClient.newHttpClient();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
var payload = new
{
input = new { bookingID = "BK-987654321" },
settings = new { connectionCodes = new[] { "testb-hbds-1876" } }
};
using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("ApiKey", "YOUR_API_KEY");
var content = new StringContent(
JsonSerializer.Serialize(payload),
Encoding.UTF8,
"application/json");
var response = await client.PostAsync(
"https://api.bundleport.com/connect/hotels/v1/cancel",
content);
Console.WriteLine(await response.Content.ReadAsStringAsync());
Next Steps
- Retrieve Booking - Get booking details
- List Bookings - Query bookings
- Cancellation Policies - Understand cancellation rules