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

Deals API Best Practices for Integration

Last updated: 2026-03-03

Deals API Best Practices for Integration

This article covers production-ready guidance for integrating the Deals API into your application. Following these practices will help you deliver a fast, reliable deals experience while being a good API consumer.

Caching Strategies

Hotel deals change frequently, but they do not change on every request. Implementing a caching layer reduces latency, lowers API call volume, and provides a better user experience.

Recommended Cache Duration

A cache TTL (time-to-live) of 5 to 10 minutes strikes a good balance between freshness and efficiency. Deals are time-sensitive, but they do not update every second.

  • 5 minutes — Suitable for high-traffic pages where users expect up-to-the-minute deals.
  • 10 minutes — Appropriate for lower-traffic pages or background preloading.

Cache Key Design

Include all query parameters and relevant headers in your cache key to avoid serving stale or mismatched results:

deals:{lat}:{long}:{currency}:{top_destination}:{language}

Round coordinates to 2-3 decimal places in your cache key to increase cache hit rates. Two decimal places of latitude/longitude precision covers roughly 1.1 km, which is close enough for deal searches:

JAVASCRIPT
function buildCacheKey(lat, long, currency, topDestination, language) {
  const roundedLat = lat.toFixed(2);
  const roundedLong = long.toFixed(2);
  return deals:${roundedLat}:${roundedLong}:${currency}:${topDestination}:${language};
}

Server-Side Cache

If your application has a backend, cache API responses there to benefit all users requesting deals for the same area:

JAVASCRIPT
const cache = new Map();

async function getDeals(lat, long, currency, options = {}) {
const key = buildCacheKey(lat, long, currency, options.topDestination, options.language);
const cached = cache.get(key);

if (cached && Date.now() - cached.timestamp < 5 60 1000) {
return cached.data;
}

const data = await fetchDealsFromAPI(lat, long, currency, options);
cache.set(key, { data, timestamp: Date.now() });
return data;
}

For production systems, consider using Redis or Memcached instead of an in-memory cache.

Client-Side Cache

On the frontend, you can use session storage or an in-memory store to avoid redundant calls when users navigate back to the deals page:

JAVASCRIPT
function getCachedDeals(key) {
  const raw = sessionStorage.getItem(key);
  if (!raw) return null;

const { data, timestamp } = JSON.parse(raw);
if (Date.now() - timestamp > 5 60 1000) {
sessionStorage.removeItem(key);
return null;
}
return data;
}

Polling Frequency

If your application displays deals on a long-lived page (such as a dashboard or homepage), periodically refresh the data to keep it current.

Recommended Intervals

ScenarioInterval
Active deals page (user viewing)5–10 minutes
Background tabPause polling
Homepage widget10–15 minutes
Mobile app (foreground)5–10 minutes
Mobile app (background)Do not poll

Pause When Not Visible

Avoid wasting API calls when the user is not looking at the page:

JAVASCRIPT
let pollTimer = null;

function startPolling(fetchFn, intervalMs) {
fetchFn();
pollTimer = setInterval(fetchFn, intervalMs);
}

function stopPolling() {
clearInterval(pollTimer);
pollTimer = null;
}

document.addEventListener('visibilitychange', () => {
if (document.hidden) {
stopPolling();
} else {
startPolling(fetchDeals, 5 60 1000);
}
});

Error Handling

Robust error handling ensures your deals feature degrades gracefully rather than breaking the page.

HTTP Status Codes

StatusMeaningAction
200SuccessParse and display the deals.
400Bad RequestCheck your parameters. Likely an invalid lat, long, or currency value.
401UnauthorizedVerify your API credentials and authentication headers.
404Not FoundConfirm the endpoint URL is correct.
429Too Many RequestsYou have exceeded the rate limit. Back off and retry after the indicated period.
500Internal Server ErrorRetry with exponential backoff. If persistent, contact Xeni support.
503Service UnavailableThe API is temporarily down. Retry after a short delay.

Retry with Exponential Backoff

For transient errors (429, 500, 503), implement exponential backoff:

JAVASCRIPT
async function fetchWithRetry(url, options, maxRetries = 3) {
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    try {
      const response = await fetch(url, options);

if (response.ok) {
return response.json();
}

if (response.status === 429 || response.status >= 500) {
if (attempt < maxRetries) {
const delay = Math.pow(2, attempt) 1000 + Math.random() 1000;
await new Promise(resolve => setTimeout(resolve, delay));
continue;
}
}

throw new Error(API returned ${response.status}: ${response.statusText});
} catch (error) {
if (attempt === maxRetries) throw error;
const delay = Math.pow(2, attempt) * 1000;
await new Promise(resolve => setTimeout(resolve, delay));
}
}
}

Handling No Results

A successful response with an empty deals array is not an error. Handle it as a normal state in your UI:

  • Show a friendly "No deals available" message.
  • Suggest the user try a different location or check back later.
  • Optionally, fall back to a top_destination=true query to display popular deals instead.

Rate Limiting

While the exact rate limits depend on your API plan, follow these general guidelines:

  • Do not call the API on every keystroke or scroll event. Debounce location changes and user interactions.
  • Use caching to serve repeated requests from your cache rather than hitting the API.
  • Monitor your usage and set up alerts if you approach your rate limit threshold.
  • Respect 429 responses by backing off as described above.

Combining Deals with Hotel Search

The Deals API is a discovery tool — it shows users what discounts are available. To complete a booking, you will typically need to use the Hotels API.

A recommended flow:

  1. Show deals — Use the Deals API to display attractive offers on your homepage or deals page.
  2. User selects a deal — When a user clicks on a deal, capture the property ID.
  3. Check availability — Call the Hotels API availability endpoint with the property ID, check-in/check-out dates, and guest count.
  4. Confirm pricing — Use the Hotels API price confirmation endpoint to lock in the rate.
  5. Complete booking — Proceed through the Hotels API booking flow.

This handoff from Deals to Hotels API gives users the best experience: they discover deals easily and then transition into a full booking flow with confirmed, real-time pricing.

Correlation and Session ID Best Practices

  • x-correlation-id — Generate a new UUID for every API call. This makes it easy to trace individual requests in logs.
  • x-session-id — Reuse the same UUID for all API calls within a single user session. This helps Xeni correlate requests from the same user journey.
  • Log both IDs — Store both IDs in your application logs. If a user reports an issue, you can provide these to Xeni support for rapid debugging.

Performance Tips

  • Lazy load deal images — Use loading="lazy" on deal card images to avoid blocking the initial page render.
  • Preload deals for common locations — If your app serves a specific market, preload deals for major cities in that region.
  • Use server-side rendering — For SEO and initial load performance, render deal cards on the server and hydrate on the client.
  • Minimize layout shift — Reserve space for deal cards (e.g., using skeleton cards) so the page does not jump when data loads.

Was this article helpful?