Most write-ups about "AI agents in production" focus on prompts, tool-calling, and orchestration frameworks. Almost none of them talk about what happens when your agent's tools are a 15-year-old hotel Property Management System (PMS) with a SOAP-flavored REST API, eventual-consistency inventory, and a rate limit that was clearly set for a human clicking buttons, not a model firing requests in a loop.
We've spent the last year building AI agents — chat, voice, and email — that book real rooms in real PMS platforms (Opera, Mews, Cloudbeds, Apaleo, and a handful of regional ones nobody outside hospitality has heard of). This is a rundown of the integration problems that actually ate our time, and how we ended up solving them.
- "Real-time availability" is a polite fiction
Every PMS vendor advertises real-time inventory. In practice, most expose availability through an endpoint that's a cached read replica, refreshed on an interval measured in seconds to low minutes. That's fine for a human refreshing a dashboard. It's a problem when an AI agent tells a guest "yes, that room is available" and the booking write fails four seconds later because someone else just took it.
What worked for us:
Treat every "available" response as provisional, not confirmed, until the write succeeds.
Hold a short-lived soft lock (5–15 seconds) on the room type at the point of quoting a rate, if the PMS supports it — and if it doesn't, compensate with optimistic booking + graceful failure messaging.
Never let the agent promise a room in natural language before the booking call returns 2xx. This sounds obvious, but it's an easy trap when you're streaming a conversational response token-by-token and the booking call hasn't resolved yet.
availability = pms.check_availability(room_type, dates)
if availability.likely_available:
# do NOT say "confirmed" yet
booking = pms.create_booking(...)
if booking.success:
respond("You're all set — confirmed for...")
else:
respond("That room just got taken — here's the next best option...")
2. Idempotency is not optional when the caller is a language model
A human booking a room clicks "Confirm" once. An agent, especially one built on a ReAct-style loop with retries, can absolutely call your booking tool twice for the same intent — a timeout, a retry policy, a hallucinated re-attempt after a slow response. If your PMS integration isn't idempotent, you get double bookings, and double bookings are the fastest way to lose a hotel partner's trust.
Our fix was boring but effective: every booking request carries a client-generated idempotency key derived from the conversation ID + intent hash. The integration layer checks that key against a short-term store before ever calling the PMS write endpoint. Not every PMS API supports idempotency keys natively, so in several cases we had to build this layer ourselves in front of vendors that didn't.
3. Auth is a different problem per vendor, and it will not be abstracted away cleanly
OAuth2 client-credentials for one vendor. A static API key plus IP allowlisting for another. A "sign this request with the property's proprietary hash function" scheme for a third (yes, really). If you're integrating with more than two or three PMS vendors, resist the urge to build one clever unified auth abstraction too early — you'll spend more time fighting the abstraction than the actual vendors.
What worked better: a thin adapter interface (authenticate(), refresh(), is_valid()) per vendor, with vendor-specific implementations underneath, and a scheduler that proactively refreshes tokens before expiry rather than reacting to 401s. Reacting to 401s mid-conversation means your guest is mid-sentence with the agent while you're silently re-authenticating in the background — survivable, but avoidable.
4. Webhooks from PMS vendors are unreliable enough that polling is sometimes the safer default
We initially assumed webhooks (booking updates, cancellations, rate changes) would be the backbone of keeping agent context in sync with the PMS. Reality: webhook delivery guarantees vary wildly by vendor, some don't support them at all, and the ones that do occasionally silently stop firing after an account-level config change with zero notification.
Our current approach is a hybrid:
Webhooks where available, treated as a freshness hint, not a source of truth.
A reconciliation poll on a short interval for anything actively referenced in an open conversation.
A slower background poll for general inventory/rate sync.
This costs more API calls than a pure webhook model, but it means a guest never gets an answer based on state that's silently gone stale.
5. Latency budgets matter more for voice than for chat, and PMS calls are usually your bottleneck
A chat agent can tolerate a couple of seconds of "thinking." A voice agent on a phone call cannot — anything past ~700ms–1s of dead air starts to feel broken, and hotel guests calling about a room tonight are not a patient audience.
Most PMS APIs were never designed with that latency budget in mind. Our answer was to decouple the conversational turn from the PMS round-trip wherever the interaction allows it: acknowledge and keep the guest engaged ("let me check that for you now") while the availability/booking call runs, rather than blocking the entire turn on the API response. For the small number of PMS integrations with genuinely slow endpoints (2s+), this pattern is the difference between a voice agent that feels responsive and one that feels broken.
6. Guest profile merging is a data problem before it's an AI problem
Multi-channel agents (voice, WhatsApp, email, web chat) mean the same guest can show up through four different identifiers with no obvious common key — a phone number here, an email there, a booking reference from six months ago. Getting this wrong means the agent "forgets" a returning guest's preferences or, worse, merges two different guests' data.
We settled on a conservative matching strategy: hard-match on verified identifiers (confirmed email, confirmed phone via OTP where possible), soft-match with human confirmation for anything fuzzier ("I see a previous stay under this name — is that you?"). Over-eager fuzzy matching caused more trust problems than it solved.
The pattern underneath all of this
Every one of these problems has the same shape: the PMS was built for humans operating at human speed and human error tolerance, and an AI agent violates both assumptions. It calls faster, retries more aggressively, and needs sub-second responses in contexts where the original API was designed around a person reading a screen.
None of this is a reason to avoid building on top of legacy hospitality infrastructure — it's just the actual engineering work that "AI agent + PMS integration" involves, underneath the parts that make it into the demo video.
Book A Demo https://huemanai.co.uk/

Top comments (0)