meridian.app
AI Booking Agent
A booking concierge that compares options in conversation, holds a reservation, and charges only after an explicit confirm.
- Hold first
- charge only on confirm
- Web + phone
- including voice
Web app screen: Search, with Chat on a phone. 1 of 3
Happy to help. I have Saturday, Oct 10 around 8:00 PM, somewhere quiet, under $200 with free cancellation. How many people will be joining?
Updated, no need to start over. I kept quiet, under $200, and free cancellation. Three places fit everything:
Osteria Lume
Saffron House
Juniper Table
Got it: Sat, Oct 10 around 8:00 PM. How many people?
Updated, everything else kept. 3 places fit:
Osteria Lume
Saffron House
Problem
A dinner for six, a hotel with a price ceiling, a haircut next Friday: each one starts as a sentence and then gets retyped into a form. If the guest changes the time or the party size, the search usually starts over, and the charge can land before the cancellation terms are obvious.
Solution
Meridian keeps the request in the thread. It shows the fields it understood, updates them when the guest corrects it, and holds the table while a countdown runs. The deposit is a separate step, with the policy and the card on file in view, and the pay button waits for a checked consent line.
- Built the guest app and admin console in Next.js 16, TypeScript, and Tailwind. TanStack Query holds server state. Zustand only covers local UI.
- The API is NestJS 11 on Fastify: REST with OpenAPI, Zod on every boundary, and RBAC around bookings, payments, and handoffs.
- PostgreSQL 18 stores the booking model. PostGIS handles radius search, pgvector stays in the same database, and Redis caches availability and rate limits.
- Temporal runs the hold, the payment, and the human approval, with retries and compensation when a provider or a charge fails.
- The assistant uses the OpenAI Agents SDK with structured outputs, so a tool call cannot fire on a malformed intent. Stripe takes the deposit only after the guest confirms.
- Twilio covers SMS and WhatsApp. Confirmed bookings sync to Google Calendar and Outlook, receipts go to S3, and OpenTelemetry plus Sentry trace the path from the model call through payment.
When a person takes over
The operations console lists live conversations, the assistant's tool trace, and the point where a teammate stepped in.
Web app screen: Operations
Live now
186 active| Customer | Request | Channel | Status | Risk | Waiting |
|---|---|---|---|---|---|
JR Jordan R. | Dinner · 6 guests · Sat 8:30 PM | Web · EN | Awaiting confirmation | Low | 0:42 |
MG María G. | Refund outside policy · Spa | WhatsApp · ES | Needs human | Medium | 2:10 |
SO Sam O. | Hotel · Chicago · 2 nights | Voice · EN | Searching | Low | 0:08 |
PK Priya K. | Group dinner · 12 guests | Web · EN | Collecting guest details | Low | 1:15 |
AT Ana T. | Card declined twice · Hotel | Web · PT | Risk review | High | 3:02 |
CD Chris D. | Flight change · Rebooking | Voice · EN | Options sent | Low | 0:31 |
HN Hana N. | Spa day for two · Sun | WhatsApp · JA | Comparing options | Low | 0:19 |
RB Rui B. | Price watch · Hotel under $150 | Web · EN | Watching | Low | Idle |
LW Leo W. | Reschedule · Massage | SMS · EN | Confirmed | Low | Done |
Stack
Full-stack work across the Next.js guest app and admin console, the NestJS API, and the Temporal workflows that hold, charge, and hand off a booking.
- Next.js
- TypeScript
- Tailwind CSS
- NestJS
- PostgreSQL
- Redis
- Temporal
- OpenAI
- Stripe
- Twilio
- AWS
Outcomes
- Hold first
- charge only on confirm
- Web + phone
- including voice
- A guest can go from one sentence to a held table without leaving the thread, on web or phone, including by voice.
- Nothing is booked or charged until the guest confirms the final price and the cancellation terms.
- A failed provider call or a dropped worker resumes from the Temporal workflow instead of a half-finished booking.