Getting Started with the Xeni Activities APIHow to Book an ActivityHow to Browse Activity Tags and CategoriesHow to Cancel an Activity BookingHow to Check Activity AvailabilityHow to Get Activity DetailsHow to Retrieve Activity Booking DetailsHow to Search for Activities with FiltersHow to Search for Activity DestinationsCar Rental API - Getting StartedCar Rental API - Understanding Response FieldsHow to Book a Car RentalHow to Get Rental Car Details and Equipment Add-OnsHow to Retrieve or Cancel a Car Rental BookingHow to Search for Available Rental CarsHow to Search for Pickup LocationsHow to Use Car Rental Search FiltersDeals API Best Practices for IntegrationDeals API Frequently Asked QuestionsGetting Started with the Xeni Deals APIDeals API Request Parameters and Headers ReferenceDeals API Supported Currencies and LocalizationHow to Display Deals in Your ApplicationHow to Fetch Hotel Deals by LocationFlights API Error Codes and TroubleshootingGetting Started with the Xeni Flights APIHow to Book a FlightHow to Check Flight Availability and PricingHow to Confirm or Cancel a Flight BookingHow to Retrieve Fare Rules for a FlightHow to Retrieve Flight Booking DetailsHow to Search for Airports Using AutocompleteHow to Search for FlightsHow to Use Flight Search Filters, Sorting, and PaginationHow to Check Room Availability and PricingHow to Filter Vacation Rental ResultsHow to Get Resort Property Details, Amenities, and AccessibilityHow to Hold and Confirm a Resort BookingHow to Release a Resort HoldHow to Retrieve Resort Booking DetailsHow to Search for Available ResortsHow to Search for Resort DestinationsHow to Search for Vacation Rental LocationsHow to Search for Vacation RentalsHow to Use Resort Search Filters and SortingGetting Started with the Xeni Resorts APIResorts API: Understanding Booking Statuses and PoliciesGetting Started with the Vacation Rentals APIVacation Rentals Frequently Asked QuestionsVacation Rentals Supported Property TypesUnderstanding Async Search for Vacation RentalsAuthentication & API SignaturesBooking Hotels — Direct API & SSO CheckoutError Handling, Rate Limits & Best PracticesGetting Started with the Xeni Hotels APIManaging Bookings: Status, Retrieval & CancellationPricing Confirmation & Token LifecycleRetrieving Hotel Details & Room AvailabilitySearching for Hotels: Locations, Filters & PaginationSearching for HotelsSession Management & Correlation IDsAPI authentication and getting your API keys

Booking Hotels — Direct API & SSO Checkout

Last updated: 2026-02-13

Booking Hotels — Direct API & SSO Checkout

Once you've confirmed pricing and received a pricing token, there are two ways to complete a hotel booking through the Xeni API. This article covers both approaches.

Booking Options at a Glance

MethodHow It WorksBest For
Direct API BookingCall the booking endpoint programmatically. Process payments through your own merchant account or through Xeni's payment processing.Enterprise integrations, white-label platforms, custom checkout flows.
SSO CheckoutRedirect the guest to Xeni's hosted checkout page where they enter payment details and complete the booking.Quick integrations where you don't want to handle payment processing.

*

Option 1: Direct API Booking

The direct API approach gives you full control over the booking experience. You collect guest details, process payment through your own merchant account (or Xeni's), and call the Xeni booking endpoint to create the reservation.

Endpoint

POST /hotels/api/v2/bookings?pricingtoken={pricingtoken}

Query Parameters

ParameterTypeRequiredDescription
pricingtokenstringYesThe pricingtoken from the price confirmation response. Not the availability token.

Request Body

FieldTypeRequiredDescription
bookingidstringYesA unique booking identifier generated by your system.
roomsarrayYesArray of guest objects, one per room.
rooms[].titlestringYesGuest title (e.g., "Mr", "Ms", "Mrs").
rooms[].firstnamestringYesGuest first name.
rooms[].lastnamestringYesGuest last name.
emailstringYesGuest email address for booking confirmation.
phoneobjectYesGuest phone number.
phone.countrycodestringYesPhone country code (e.g., "1" for US).
phone.numberstringYesPhone number (digits only).

Example Request

POST /hotels/api/v2/bookings?pricingtoken=eyJhbGciOiJIUzI1NiJ9.pricingfinal...Authorization: {signature}x-correlation-id: {correlation_id}Content-Type: application/json

{ "bookingid": "XENI-1700000000-ABC123DEF", "rooms": [ { "title": "Mr", "firstname": "John", "lastname": "Smith" } ], "email": "john.smith@example.com", "phone": { "countrycode": "1", "number": "5551234567" }}

Example Response

JSON
{
  "data": {
    "booking_id": "XENI-1700000000-ABC123DEF",
    "confirmation_number": "HTL-98765",
    "booking_status": "confirmed"
  }
}

Payment Processing

When using the direct API approach, you have two options for handling payments:

  • Your own merchant account — Process the payment through your existing payment processor (Stripe, Braintree, Adyen, etc.) before or after calling the Xeni booking endpoint. This gives you full control over the payment experience, fees, and reconciliation.
  • Xeni's payment processing — Use Xeni's merchant to handle payment collection. Contact your Xeni account representative for details on enabling this option and the available payment methods.

Recommended for enterprise: Most enterprise clients use the direct API booking with their own payment processor. This gives you complete control over the checkout UX, payment methods, and financial reconciliation.

*

Option 2: SSO Checkout (Hosted Page)

If you prefer not to handle payment processing, Xeni provides a hosted checkout page. You generate a URL with the booking parameters and redirect the guest to it. Xeni handles payment collection and booking confirmation on the hosted page.

Benefit: SSO checkout eliminates the need for your application to handle sensitive payment data. All payment processing is handled by Xeni's PCI-compliant checkout infrastructure.

Checkout Environments

EnvironmentCheckout Base URL
UAT (Sandbox)https://lifestyle2.uat.booking.clubxeni.com
Productionhttps://lifestyle2.booking.clubxeni.com

Checkout URL Structure

The checkout URL follows this pattern:

JSON
{checkoutbaseurl}/booknow/hotels/v2/checkout?{parameters}

Required Parameters

All parameters are passed as URL query string values. Objects and arrays must be JSON-stringified and URL-encoded.

ParameterTypeDescription
correlationIdstringThe correlation ID from the current search session.
startDatestringCheck-in date in YYYY-MM-DD format.
endDatestringCheck-out date in YYYY-MM-DD format.
locationJSON stringLocation object (see format below).
occupancyJSON stringOccupancy array (see format below).
pricingTokenstringThe pricingtoken from the price confirmation response. Not the availability token.
propertyIdstringThe hotel's propertyid.
roomIdstringThe room id from the availability response.
stayPeriodJSON stringStay period object with start and end dates.
nationalityJSON stringGuest nationality object.
forceGetstringSet to "true".
isOTAstringSet to "true" for OTA integrations.
pagingJSON stringPaging configuration object.
preferenceJSON stringSet to "[]" (empty JSON array).

*

Parameter Formats

Location Object

JSON
{
  "id": "12345",
  "name": "Miami",
  "full_name": "Miami, Florida, United States",
  "country": "United States",
  "type": "City",
  "location": {
    "lat": 25.7617,
    "long": -80.1918
  }
}

Use the location data returned by the autocomplete endpoint. The id must be a string.

Occupancy Array

JSON
[
  {
    "id": "room11700000000",
    "numOfRoom": 1,
    "adults": 2,
    "childs": 0,
    "childages": []
  }
]

Each element represents one room. The id field should be a unique identifier (any string).

Stay Period Object

JSON
{
  "start": "2025-06-01",
  "end": "2025-06-05"
}

Nationality Object

JSON
{
  "name": "United States",
  "alpha2Code": "US"
}

Paging Object

JSON
{
  "pageNo": 1,
  "pageSize": 50
}

*

Full Example: Building the Checkout URL

JavaScript

function generateCheckoutUrl(params) {  const baseUrl = 'https://lifestyle2.uat.booking.clubxeni.com';

const location = { id: String(params.location.id), name: params.location.name, fullname: params.location.fullname, country: params.location.country, type: params.location.type || 'City', location: { lat: params.location.lat, long: params.location.long } };

const occupancy = params.occupancy.map((occ, index) => ({ id: room${index + 1}${Date.now()}, numOfRoom: 1, adults: occ.adults, childs: occ.childs || 0, childages: occ.childages || [] }));

const urlParams = new URLSearchParams({ correlationId: params.correlationId, startDate: params.startDate, endDate: params.endDate, forceGet: 'true', isOTA: 'true', location: JSON.stringify(location), nationality: JSON.stringify({ name: 'United States', alpha2Code: 'US' }), occupancy: JSON.stringify(occupancy), paging: JSON.stringify({ pageNo: 1, pageSize: 50 }), preference: JSON.stringify([]), pricingToken: params.pricingToken, propertyId: params.propertyId, roomId: String(params.roomId), stayPeriod: JSON.stringify({ start: params.startDate, end: params.endDate }) });

return ${baseUrl}/booknow/hotels/v2/checkout?${urlParams.toString()};}

Python

import jsonfrom urllib.parse import urlencode

def generatecheckouturl(params): base_url = "https://lifestyle2.uat.booking.clubxeni.com"

location = { "id": str(params["location"]["id"]), "name": params["location"]["name"], "fullname": params["location"]["fullname"], "country": params["location"]["country"], "type": params["location"].get("type", "City"), "location": { "lat": params["location"]["lat"], "long": params["location"]["long"] } }

occupancy = [{ "id": f"room{i+1}{int(time.time())}", "numOfRoom": 1, "adults": occ["adults"], "childs": occ.get("childs", 0), "childages": occ.get("childages", []) } for i, occ in enumerate(params["occupancy"])]

query = urlencode({ "correlationId": params["correlationid"], "startDate": params["startdate"], "endDate": params["enddate"], "forceGet": "true", "isOTA": "true", "location": json.dumps(location), "nationality": json.dumps({"name": "United States", "alpha2Code": "US"}), "occupancy": json.dumps(occupancy), "paging": json.dumps({"pageNo": 1, "pageSize": 50}), "preference": json.dumps([]), "pricingToken": params["pricingtoken"], "propertyId": params["propertyid"], "roomId": str(params["roomid"]), "stayPeriod": json.dumps({"start": params["startdate"], "end": params["enddate"]}) })

return f"{base_url}/booknow/hotels/v2/checkout?{query}"

*

Presenting the Checkout Link

Once you've built the URL, present it to the guest. Common approaches:

  • Button redirect — Display a "Complete Booking" button that opens the checkout URL in a new tab.
  • Automatic redirect — Navigate the user directly to the checkout page.
  • Embedded iframe — Embed the checkout page within your application (check with your Xeni representative for iframe compatibility).

Example: HTML Button

<a href="{checkouturl}" target="blank" rel="noopener noreferrer"   style="display: inline-block; padding: 12px 24px;          background-color: #2196F3; color: white;          text-decoration: none; border-radius: 6px;">  Complete Booking</a>

*

Important Considerations

  • Pricing token expiration: The pricing token is valid for 10 minutes. Generate the checkout URL promptly after price confirmation. If the guest delays, you may need to re-confirm the price.
  • One-time use: Each pricing token can be used for a single booking. After checkout is completed (or the token expires), a new token must be obtained for any subsequent booking.
  • Correlation ID format: The correlation ID must be passed as-is from the API response headers. Do not modify it.
  • URL encoding: JSON objects in query parameters must be properly URL-encoded. Use URLSearchParams (JavaScript) or urllib.parse.urlencode (Python) to handle encoding automatically.
* ](#article-7)_

Was this article helpful?