An AI Receptionist That Books Appointments
A provider-agnostic booking agent, grounded in a real schedule
Options on the table
Architecture at a glance
Background
This started as a side project I built for myself, to see how far a chat-first booking flow could go while staying genuinely safe. The example is a dental clinic because that is a concrete scheduling problem, but nothing inside is dental: the same product runs a physiotherapy or eye clinic by changing the list of treatments and staff.
A patient opens a web page, types or speaks, and the assistant answers and books their appointment. It runs on the clinic's own machine, so the patient list stays with them. The only thing that leaves is the conversation itself, sent to the AI company that writes the replies, never the database.
How it works
A booking reads like a normal front-desk conversation, in a few short messages:
- Ask: The patient says what they need. The assistant answers from real information: the treatment, the price, which professionals do it, and the times that are actually open.
- Verify: When the patient picks a time, the assistant emails a 6-digit code and asks for it back. That one step proves the email is real, so the confirmation and calendar invite have somewhere to go.
- Book: The assistant writes the appointment and emails a confirmation with the calendar invite attached, so it drops straight into the patient's calendar.
What it will not do (on purpose)
The safety of the assistant is mostly a list of things it cannot do, and that list is enforced, not merely intended:
- Never invents: Every time and price comes from the real schedule and price list. There is no tool for making one up.
- Never double-books: The database refuses a second overlapping booking at the moment of writing, so even two taps in the same second cannot collide.
- Never books as someone else: A patient can only see and change their own appointments; the login code, not a password, is what proves who they are.
- Stays in its lane: Asked about anything outside the clinic's treatments and appointments, it says so. It can only do what its tools allow, and there is no tool for anything else.
Provider-agnostic by design
The product is not tied to any AI company. Most vendors copy the OpenAI message format, so a single adapter already covers OpenAI, Anthropic, Gemini and OpenRouter; adding one of those is a new row in a table, not new code. Bedrock and Google's native API get their own thin adapters.
Because the assistant uses AI for three separate jobs — the brain that writes replies, the ears that turn speech to text, and the mouth that turns text back to speech — each one chooses its provider independently. A clinic can run a cheap model for the conversation and pay for quality only where the patient actually hears it. Each role also takes a backup chain: if the first provider fails or is slow, the next answers the same message and the patient sees no error.
Why PostgreSQL
A booking links a patient, a professional and a treatment, and a professional only does some treatments. That is rows and links, which is what a relational database is for. Between the relational options I chose PostgreSQL for one reason: it can refuse two overlapping bookings by itself. My own code might let both through under load, but the database checks at the moment it writes, one write at a time, so the second is rejected. Double-booking is the one mistake this product cannot make, and that guarantee lives in the database, not in hopeful application logic.