Hotel Booking Engine Integration: Cloudbeds, Mews & SiteMinder API Guide
I've spent the last three years building custom booking interfaces for independent hotels and boutique hospitality groups. The one thing I can tell you with certainty: every hotel PMS API has at least one undocumented behavior that will ruin your weekend. This guide covers what I've actually learned integrating with Cloudbeds, Mews, and SiteMinder — the good, the bad, and the rate-plan-that-disappeared-at-2am.
If you're a developer tasked with building a native booking UI that bypasses the generic iFrame widget these platforms ship, or a hotel operator tired of the cookie-cutter booking experience, this is for you. We'll cover API architecture, authentication patterns, real-time availability, rate management, and the frontend patterns that actually convert guests.
Table of Contents
- Why Build a Custom Booking Engine?
- Understanding the Hotel Tech Stack
- Cloudbeds API Integration
- Mews API Integration
- SiteMinder API Integration
- Platform Comparison
- Building the Native Booking UI
- Real-Time Availability and Rate Sync
- Payment Processing and PCI Compliance
- Performance and Conversion Optimization
- Deployment Architecture
- FAQ

Why Build a Custom Booking Engine?
The default booking widgets from Cloudbeds, Mews, and SiteMinder work. They'll take a reservation and push it into the PMS. But they come with serious trade-offs:
- Brand dilution: iFrame-based widgets look foreign on a beautifully designed hotel website. They break the visual flow, and guests notice.
- Limited customization: Want to show a room comparison table? Upsell a spa package inline? Display dynamic pricing tied to local events? Good luck doing that inside a widget.
- Performance penalties: iFrame widgets load their own CSS, JS, and tracking. On mobile — where 65%+ of hotel searches happen in 2025 — that extra weight kills conversion.
- SEO blindspot: Content inside iFrames isn't indexed. Your room descriptions, amenities, and pricing data are invisible to Google.
- Analytics gaps: Cross-domain tracking between your site and a widget domain is fragile. You lose attribution data constantly.
A custom native booking UI built on top of these platforms' APIs gives you full control. You own the design, the data flow, and the user experience. The PMS still handles the operational backend — reservations, housekeeping, channel management — but the guest-facing layer is yours.
This is exactly the kind of work we do at Social Animal through our headless CMS development practice. The hotel's marketing site lives in a modern frontend framework, and the booking engine is a first-class citizen, not an afterthought bolted on via iFrame.
Understanding the Hotel Tech Stack
Before diving into specific APIs, let's establish the landscape. Hotel technology has a few key layers:
PMS (Property Management System)
The operational brain. Manages reservations, room assignments, guest profiles, housekeeping, and billing. Cloudbeds and Mews are both PMS platforms.
Channel Manager
Distributes inventory and rates to OTAs (Booking.com, Expedia, etc.) and keeps everything in sync. SiteMinder is primarily a channel manager, though they've expanded into direct booking.
Booking Engine
The guest-facing interface where direct reservations happen. This is what we're replacing with a custom build.
CRS (Central Reservation System)
For multi-property groups, a CRS aggregates availability across locations. Some PMS platforms include this; others require a separate system.
The integration challenge is that these layers overlap. Cloudbeds bundles PMS + channel manager + booking engine. Mews is PMS-first with an open API philosophy. SiteMinder connects everything as middleware. Your custom UI needs to understand where each platform's responsibilities start and end.
Cloudbeds API Integration
Cloudbeds serves over 20,000 properties in 150+ countries as of 2025. Their API has matured significantly, but it still has some quirks.
Authentication
Cloudbeds uses OAuth 2.0 with an authorization code flow. You'll register your application in the Cloudbeds Marketplace to get client credentials.
// OAuth token exchange
const tokenResponse = await fetch('https://hotels.cloudbeds.com/api/v1.2/access_token', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
grant_type: 'authorization_code',
client_id: process.env.CLOUDBEDS_CLIENT_ID,
client_secret: process.env.CLOUDBEDS_CLIENT_SECRET,
redirect_uri: process.env.CLOUDBEDS_REDIRECT_URI,
code: authorizationCode,
}),
});
One gotcha: Cloudbeds access tokens expire after 300 seconds (5 minutes). Yes, five minutes. You absolutely need a token refresh strategy that handles this gracefully. I store tokens in a server-side cache (Redis works well) and refresh proactively at the 4-minute mark.
Key Endpoints for Booking
GET /getAvailableRoomTypes— Returns room types with availability for a date range. This is your primary endpoint for the search results page.GET /getRates— Fetches rate plans. Watch out: rates can be room-type-specific, and some won't appear unless the property has activated them.POST /postReservation— Creates a reservation. Requires guest details, room type, dates, and rate plan.GET /getHotelDetails— Property info, amenities, policies. Cache this aggressively.
Cloudbeds Pitfalls
The availability endpoint doesn't always return real-time data during high-traffic periods. I've seen delays of 15-30 seconds when a property is processing bulk OTA updates. Build your UI to handle "availability may have changed" scenarios gracefully — show a confirmation step that re-validates before collecting payment.
Also, their rate structure can be deeply nested. A single room type might have 8+ rate plans with different cancellation policies, meal inclusions, and minimum stay requirements. You need to decide upfront how much of that complexity to expose in your UI.

Mews API Integration
Mews takes a fundamentally different approach. Their Connector API is event-driven and designed for deep integration. I'd call it the most developer-friendly PMS API in the hospitality space.
Authentication
Mews uses a simpler model: a ClientToken (identifies your integration) and an AccessToken (identifies the property). No OAuth dance required for server-to-server communication.
// Mews API request
const response = await fetch('https://api.mews.com/api/connector/v1/services/getAvailability', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
ClientToken: process.env.MEWS_CLIENT_TOKEN,
AccessToken: process.env.MEWS_ACCESS_TOKEN,
Client: 'YourApp',
ServiceId: serviceId,
StartUtc: '2025-08-01T00:00:00Z',
EndUtc: '2025-08-07T00:00:00Z',
}),
});
Key Endpoints for Booking
services/getAvailability— Real-time availability by resource category (room type in Mews terminology).rates/getPricing— Returns pricing for specific rate plans and date ranges.reservations/add— Creates one or more reservations atomically.customers/add— Creates guest profiles separately from reservations. Mews keeps these decoupled, which is actually nice for returning guest detection.
Mews WebSockets
Here's where Mews really shines. They offer WebSocket connections for real-time updates:
// Subscribe to reservation changes
const ws = new WebSocket('wss://ws.mews.com/ws/connector');
ws.onopen = () => {
ws.send(JSON.stringify({
ClientToken: process.env.MEWS_CLIENT_TOKEN,
AccessToken: process.env.MEWS_ACCESS_TOKEN,
}));
};
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
// Handle availability changes in real-time
if (data.Type === 'Reservation') {
invalidateAvailabilityCache(data.ServiceId);
}
};
This means your booking UI can reflect availability changes instantly — no polling required. When another guest books the last deluxe room, your other visitors see it disappear in real-time.
Mews Pitfalls
Mews uses UUIDs for everything, and their data model is highly normalized. A simple "get me available rooms with prices" requires hitting 3-4 endpoints and joining the data yourself. The API is powerful but verbose. Build a solid data aggregation layer on your server.
Also, Mews's sandbox environment doesn't perfectly mirror production behavior for payment-related flows. Test thoroughly in a staging property before going live.
SiteMinder API Integration
SiteMinder sits in a different position — it's primarily a channel manager and distribution platform. Their API (the Platform API and the older Channel Manager API) focuses on rate and availability distribution.
Authentication
SiteMinder uses API keys with OAuth 2.0 client credentials flow:
const tokenResponse = await fetch('https://api.siteminder.com/oauth/token', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
grant_type: 'client_credentials',
client_id: process.env.SITEMINDER_CLIENT_ID,
client_secret: process.env.SITEMINDER_CLIENT_SECRET,
scope: 'availability:read reservations:write',
}),
});
Key Considerations
SiteMinder's direct booking API is more restrictive than Cloudbeds or Mews. You're essentially building on top of their TheBookingButton product's backend. The API allows:
- Availability queries by property and date range
- Rate retrieval with restrictions (min stay, closed to arrival, etc.)
- Reservation creation with guest details
- Modification and cancellation workflows
The advantage of SiteMinder is that it connects to 400+ PMS systems. If your hotel client uses an obscure PMS, SiteMinder might be your only viable API integration path for a custom booking UI.
SiteMinder Pitfalls
Rate updates through SiteMinder can lag behind the source PMS by 1-3 minutes. For high-demand properties, this creates overbooking risk. Always implement a pre-payment availability check that goes through the most real-time path available.
Their API documentation is... functional. Expect to lean on their partner support team for edge cases. Response to developer inquiries has improved in 2025, but budget extra time for the integration.
Platform Comparison
| Feature | Cloudbeds | Mews | SiteMinder |
|---|---|---|---|
| API Style | REST (v1.2) | REST + WebSockets | REST |
| Auth Method | OAuth 2.0 (auth code) | Token-based | OAuth 2.0 (client creds) |
| Real-time Updates | Polling only | WebSockets | Webhooks |
| Rate Limit | 120 req/min | 1000 req/min | 60 req/min |
| Sandbox Environment | Yes | Yes | Yes (limited) |
| Multi-property Support | Via separate tokens | Native | Native |
| Booking API Maturity | Good | Excellent | Moderate |
| Documentation Quality | Good | Excellent | Fair |
| Typical Integration Time | 3-4 weeks | 2-3 weeks | 4-6 weeks |
| Monthly API Cost (2025) | Included in PMS plan | Included in PMS plan | Varies by tier |
Building the Native Booking UI
Now for the fun part — actually building the thing. I'll focus on patterns rather than a specific framework, though we typically build these with Next.js or Astro depending on the project requirements.
The Booking Flow Architecture
A hotel booking flow has 5 distinct steps:
- Search — Dates, guests, rooms
- Results — Available room types with rates
- Selection — Room and rate plan choice, add-ons
- Guest Details — Contact info, special requests
- Payment & Confirmation — Secure payment, booking confirmation
Each step should be its own route (not a multi-step form on one page). This gives you:
- Deep-linkable URLs (great for marketing campaigns)
- Better analytics per step
- Easier error recovery
- Browser back-button support that doesn't break everything
Search Component
// Next.js server action for availability search
'use server'
import { getAvailability, getRates } from '@/lib/pms-client';
export async function searchAvailability(formData: FormData) {
const checkIn = formData.get('checkIn') as string;
const checkOut = formData.get('checkOut') as string;
const adults = parseInt(formData.get('adults') as string);
const children = parseInt(formData.get('children') as string);
const [availability, rates] = await Promise.all([
getAvailability({ checkIn, checkOut }),
getRates({ checkIn, checkOut }),
]);
// Merge availability with pricing
const rooms = mergeAvailabilityWithRates(availability, rates, { adults, children });
// Filter out rooms that can't accommodate the guest count
return rooms.filter(room =>
room.maxOccupancy >= adults + children
);
}
Room Display Patterns That Convert
After A/B testing across multiple hotel sites, here's what works:
- Lead with the room photo, not the price. Hotels sell experiences, not transactions.
- Show the total stay price prominently, with the per-night price secondary. Guests think in trip budgets.
- Display cancellation policy upfront. The #1 anxiety for direct bookers is "what if my plans change?" Putting "Free cancellation until [date]" near the price increases conversion by 12-18% in our tests.
- Limit rate plan choices to 3 per room type. More than that creates decision paralysis.
- Use urgency honestly. "2 rooms left" is fine if it's true. Don't fake scarcity.
Add-On and Upsell Integration
This is where custom UIs really outperform widgets. After room selection, present relevant add-ons:
// Fetch add-ons relevant to the booking context
async function getContextualAddOns(booking: BookingContext) {
const addOns = await pmsClient.getServices();
return addOns
.filter(addOn => {
// Only show spa packages for stays > 2 nights
if (addOn.category === 'spa' && booking.nights < 3) return false;
// Show airport transfer if arriving on check-in day
if (addOn.category === 'transfer') return true;
// Show breakfast if not included in rate
if (addOn.category === 'breakfast' && !booking.ratePlan.includesBreakfast) return true;
return addOn.category === 'general';
})
.sort((a, b) => b.conversionRate - a.conversionRate)
.slice(0, 4); // Show max 4 add-ons
}
We've seen add-on revenue increase 35-50% when moving from a generic widget to a context-aware custom UI. That alone often justifies the development investment.
Real-Time Availability and Rate Sync
The biggest technical challenge isn't the booking flow — it's keeping availability accurate between your UI and the PMS.
Caching Strategy
You need caching (the PMS APIs are too slow and rate-limited for direct calls on every page load), but stale availability causes overbookings. Here's the pattern I use:
// Multi-layer caching with aggressive invalidation
const CACHE_TTL = {
availability: 60, // 1 minute
rates: 300, // 5 minutes
hotelDetails: 86400, // 24 hours
roomTypes: 3600, // 1 hour
};
async function getCachedAvailability(params: SearchParams) {
const cacheKey = `avail:${params.propertyId}:${params.checkIn}:${params.checkOut}`;
// Check cache
const cached = await redis.get(cacheKey);
if (cached) return JSON.parse(cached);
// Fetch fresh data
const fresh = await pmsClient.getAvailability(params);
await redis.setex(cacheKey, CACHE_TTL.availability, JSON.stringify(fresh));
return fresh;
}
For Mews, use the WebSocket connection to invalidate cache entries proactively. For Cloudbeds and SiteMinder, set up webhook listeners if available, or fall back to polling on a 30-second interval for high-traffic properties.
The Double-Check Pattern
Always re-validate availability at the payment step. The flow looks like:
- Guest searches → cached availability (fast, possibly slightly stale)
- Guest selects room → fresh availability check (confirm the room is still available)
- Guest enters details → no additional check needed
- Guest clicks "Book" → atomic availability check + reservation creation
Step 4 is critical. Both Mews and Cloudbeds handle this atomically in their reservation creation endpoints — if the room isn't available, the API returns an error rather than creating the booking. Don't try to check-then-book as two separate calls; you'll create race conditions.
Payment Processing and PCI Compliance
Hotel payments are uniquely complex because of pre-authorization and delayed capture patterns. A guest books today, you authorize their card, but you don't capture the charge until check-in or check-out.
Stripe Integration Pattern
Stripe is the most common payment processor we integrate for hotel clients. Here's the flow:
// Create a payment intent with manual capture
const paymentIntent = await stripe.paymentIntents.create({
amount: totalInCents,
currency: property.currency,
capture_method: 'manual', // Authorize now, capture later
metadata: {
pms_reservation_id: reservation.id,
property_id: property.id,
check_in: booking.checkIn,
check_out: booking.checkOut,
},
});
Important: You must capture within 7 days with Stripe (previously it was 7 days for most card types, now some support up to 31 days). For bookings more than a week out, you'll need to either charge immediately with a refund policy, or implement a pre-arrival capture workflow.
PCI Compliance
If you're using Stripe Elements or similar tokenized payment forms, you're handling PCI compliance at SAQ-A level, which is manageable. Never, ever send raw card numbers through your server. The PMS APIs that accept card details (Mews has this capability) should only receive tokenized or encrypted card data.
Performance and Conversion Optimization
Hotel booking conversion rates for direct channels hover around 2-3% industry-wide. A well-built custom UI can push that to 4-6%. Here's what moves the needle:
- Sub-2-second search results: Pre-fetch availability for popular date ranges. Use ISR (Incremental Static Regeneration) for property pages.
- Mobile-first date picker: The default HTML date input is terrible on mobile. Use a purpose-built component. I like
react-day-pickerwith custom touch-friendly styling. - Progressive disclosure: Don't show all rate details upfront. Let guests expand what they care about.
- Trust signals: Display "Best Rate Guarantee" prominently. Include TripAdvisor/Google review scores. Show secure payment badges near the checkout button.
- Sticky booking summary: On desktop, keep the selected room and total visible as the guest scrolls through details and payment. On mobile, use a collapsible bottom bar.
Deployment Architecture
For production hotel booking engines, here's the architecture that's served us well:
[CDN (Vercel/Cloudflare)]
→ [Next.js Frontend + API Routes]
→ [Redis Cache Layer]
→ [PMS API (Cloudbeds/Mews/SiteMinder)]
→ [Stripe Payment API]
→ [Email Service (Resend/SendGrid)]
We deploy on Vercel for most projects. Edge Functions handle the search API route so availability queries resolve from the nearest region. The PMS API calls go through a centralized Node.js serverless function with the Redis cache layer.
For multi-property hotel groups, we add a property resolver that maps the incoming domain or URL path to the correct PMS credentials and configuration. This lets one codebase serve dozens of properties.
If you're evaluating this kind of architecture, check out our pricing page for how we scope headless hospitality projects, or reach out directly to talk specifics.
FAQ
How much does it cost to build a custom hotel booking engine? For a single-property integration with one PMS (Cloudbeds, Mews, or SiteMinder), expect $15,000-$40,000 USD for the initial build depending on complexity. Multi-property deployments with shared infrastructure typically run $40,000-$80,000. Ongoing maintenance and PMS API changes add $500-$2,000/month. The ROI calculation should factor in the 2-4% uplift in direct booking conversion and the commission savings versus OTA bookings (typically 15-25% per reservation).
Can I use Cloudbeds API without their booking engine widget? Yes. Cloudbeds' API is separate from their booking engine widget. You can build a completely custom frontend that uses their API for availability, rates, and reservation creation. You'll need to be an approved Cloudbeds Marketplace partner, which involves an application and review process that takes 2-4 weeks.
Is Mews or Cloudbeds better for custom booking engine integration? Mews has the better developer experience — higher rate limits, WebSocket support, cleaner documentation, and a more normalized data model. Cloudbeds has wider market adoption among independent properties, so your client is more likely to already be using it. If starting from scratch and the client doesn't have a PMS preference, I'd recommend Mews for properties that want deep custom integration.
How do I handle overbookings with a custom booking UI? Overbookings happen when cached availability goes stale. Implement the double-check pattern: cache for search results display, but always re-validate with a fresh API call before creating the reservation. Both Mews and Cloudbeds handle atomic availability checks during reservation creation, so if you let the PMS be the source of truth at booking time, overbookings are effectively eliminated.
Do I need PCI compliance for a custom hotel booking engine? Yes, but the level depends on your implementation. Using tokenized payment solutions like Stripe Elements, Adyen Drop-in, or similar means you never handle raw card data, qualifying you for SAQ-A (the simplest PCI compliance level). If you're passing card data through your server to the PMS, you'll need SAQ-D, which is significantly more complex and expensive to maintain. Always use tokenized payments.
How does a custom booking UI affect my hotel's SEO? Positively. Room types, descriptions, amenities, and pricing rendered as native HTML (not trapped in an iFrame) are fully indexable by search engines. You can implement structured data (schema.org/Hotel, schema.org/LodgingReservation) to appear in rich results. Properties with custom-built booking pages typically see 20-40% more organic traffic to room-specific pages compared to iFrame widget setups.
Can I integrate multiple PMS platforms in one booking UI? Yes, and this is common for hotel groups where different properties use different systems. Build an abstraction layer that normalizes the API responses into a common schema. Your frontend talks to your abstraction layer, which routes to the correct PMS API based on the property. We've built this pattern for groups running Mews at urban properties and Cloudbeds at resort properties under one brand.
What happens when the PMS API goes down? Build graceful degradation. Cache the last-known availability and display it with a "prices may vary" disclaimer. Show a phone number and email prominently so guests can still reach the front desk. Implement health checks that monitor API response times and error rates, alerting your team before guests notice. For critical booking periods (holidays, events), consider a fallback that redirects to the PMS's native booking widget as a last resort.