
turno
Next.js, Supabase, Cloudflare Workers, OpenAI, Twilio, ElevenLabs
open project →watch the demo →
the main problem
Small and medium businesses spend a huge amount of time on appointment booking and management. For example, changing the time of a single appointment is a 3 to 5 minute process. Now multiply that by hundreds of appointments and you get a sense of how much time is wasted.
what I built
Turno streamlines appointment booking and management by putting AI agents on WhatsApp and on voice calls. Clients can book, reschedule or cancel appointments without a human in the loop, and they get a reminder the day before so fewer appointments are missed.
how it works
I started with a web app where businesses create their own slots and manage their appointments: a proper dashboard that also shows metrics the owner had never had before, like how many appointments get booked each month. Then I built a public page where clients, or potential clients, of the business can book an appointment super easily.
Now here comes the fun part. I asked myself: how can I cut the owner's time even further? I immediately thought about WhatsApp, because nowadays it is the standard channel between businesses and their clients. So I started digging into how to hook into WhatsApp and trigger my agent every time a message comes in.
As the number provider and wrapper over the WhatsApp API I used Twilio: a great tool, expensive though. Once I could receive messages, I needed an endpoint for Twilio to call. I looked around and went for Cloudflare Workers: they are free to start with and super easy to set up. The worker is triggered by every message and receives the text, the sender's number and a bunch of other info. It uses that to load the business and the client from my database, Supabase, and it keeps a conversation thread per phone number, so the agent remembers what was said earlier in the chat.
So now I had everything I needed to run my agent! The agent has a set of tools that trigger function calls, like get all the available slots for this day and this type of appointment, book an appointment or cancel an appointment. This is the crucial part: availability always comes from a live database query, never from the model's memory, so the agent never has to guess — which is where hallucinations would come from.
The second step was to reach the agent with a phone call instead of WhatsApp. The core doesn't change much, but instead of an endpoint that answers one message at a time you need a connection that stays open for the whole call, listening and answering in real time. Thanks to the ElevenLabs conversational agents and their Twilio integration that was pretty easy to set up, and the result was amazing!
when the agent doesn't know
What if the agent can't answer the client's question?
handing over to a human
First, the agent tries on its own: I crawl the business's website so it can answer common questions, like prices or opening hours, from what the business has already published. When the answer isn't there, both agents detect that the question is out of scope.
On WhatsApp, the agent tells the client it has asked the office and opens a ticket in the dashboard. The owner writes the answer there, and it is sent back to the client on WhatsApp.
On a voice call, the agent puts the client on hold and starts an outbound call to the business owner to ask about it, like a human receptionist would!
Both solutions are working great and the businesses are loving them.
the result
Businesses save over 30 work hours per week. Turno is currently live at multiple businesses.
what I learned
This was my first big project, built solo in just 2 months. First, I learned how to build things from the ground up so that they can scale as much as possible. And I learned to see the product as a whole, and to take it all the way to production and sell it.
the stack
web app and dashboard — Next.js, TypeScript, Tailwind CSS and shadcn/ui, Hosted on Vercel.
database and auth — Supabase (Postgres, auth, storage).
WhatsApp agent — Twilio's WhatsApp API calls a Cloudflare Worker, which runs an OpenAI assistant with function-calling tools for availability, booking and cancelling.
voice agent — ElevenLabs conversational AI, connected to phone calls through Twilio.
business knowledge — Firecrawl crawls the business's website into the info the agent answers from.
reminders — a daily Vercel cron sends each client an SMS reminder the day before, through Sweego.
testing — Braintrust evals for the agent's answers, Vitest for the web app.