The Voice Agent: How the Encore Hotel Stopped Missing Calls
Imagine you call a hotel at 11pm on a Saturday looking for a room next weekend. The voicemail picks up. You hang up. You google the next hotel. You book there instead.
That sequence used to play out at the Berlin Encore Hotel every single night. Multiply it by every week of every month — and that's the size of the problem I built the Voice Agent to fix.
Important framing: this agent answers calls. That's it. It doesn't check guests in. It doesn't replace the front desk. It picks up the phone, has a real conversation about availability, and gets a booking link into the caller's hands before they hang up. The work that requires a human still happens at the desk.

What the Caller Hears
The agent answers in under two rings, 24/7. You can talk to it the same way you'd talk to a person on the phone:
- "Do you have a room with a king bed Friday through Sunday?"
- "What's the price for two adults next weekend?"
- "Anything with two queens for the 22nd?"
It asks check-in and check-out, guest count, bed preference if it needs to. It quotes available rooms with tax-inclusive pricing — pulled live from Cloudbeds, not from a cached menu. If you want to book, it texts you a direct link to the Cloudbeds booking engine pre-populated with the dates and guest counts you just discussed. No re-typing. No second-guessing.
The whole interaction is under two minutes. Most callers don't realize it isn't a person.
The Tools
ElevenLabs runs the voice and conversation. The Node + TypeScript webhook service is what makes the agent actually able to do things during the call:
- quote_availability — queries Cloudbeds for room types, rates, and inventory for the requested dates. Returns ranked options plus a deep booking link pre-populated with dates and guests.
- get_room_types — pulls the hotel's room inventory so the agent can talk fluently about what's available without hallucinating.
- build_booking_link — generates a direct booking URL even without a quote lookup, useful for callers who already know what they want.
- send_booking_link_sms — Twilio SMS delivery with the booking link addressed to the caller by name.
- get_current_datetime — returns hotel-local date and time plus spoken forms ("Wednesday", "next Saturday") so the LLM parses relative phrases correctly.
The Cloudbeds Integration: Way Harder Than It Looked
The early version of this agent could answer the phone, but it kept quoting prices that didn't match what guests saw at checkout. Turns out Cloudbeds has multiple ways to ask for a price, and they don't all include the same taxes and fees.
The fix was an integration layer that:
- Calls
getRoomsFeesAndTaxesalongside availability so quotes are tax-inclusive. - Filters rate plans to public, flexible, refundable only — the prices a normal walk-in caller is actually eligible for.
- Falls back across Cloudbeds API versions (v1.2 → v1.1) when a method isn't available at the current version.
- Has a method allowlist in production. The agent service refuses to call any Cloudbeds endpoint that isn't on the read-only allowlist. Belt and suspenders against a prompt-injection attempt to do something destructive.
The agent is only as honest as the price it quotes. The integration layer is where honesty lives.
Security on a Public Voice Endpoint
An agent that touches a PMS and a phone system is a juicy attack surface. Decisions that turned out to matter:
- Shared secret on every tool call — ElevenLabs sends a header that's checked before any tool runs.
- OAuth admin gate — administrative endpoints require a separate OAuth flow with an admin secret, even in development.
- Strict tool field validation — agent inputs are schema-validated before they touch Cloudbeds. No "send this string straight through to the API."
- Warn-first rollout — security controls have a "warn only" mode you can flip before "enforce". Catches the legitimate calls you'd otherwise break before they hit production.
What It Replaced
Voicemail. Missed calls. The frustration of dialing a hotel after-hours and getting nobody. Now every inbound call gets answered, every caller gets a real conversation about availability, and the ones who are ready to book leave the call with a link in their pocket.
It's not a replacement for the people behind the desk. It's a replacement for the silence on the other end of the line when nobody could pick up.