A complete patient-acquisition system for a Toronto dental lead-gen and rewards operation. Three systems shipped: a marketing site with 6 SEO articles, a dashboard tracking leads through a 6-stage funnel, and an AI voice agent that calls and qualifies new leads. The whole thing runs in code, not a no-code tool.
Facebook Lead Ads bring patients in at volume. The gap was everything after the form: a lead that sits for an hour goes cold. Sending each lead to the right clinic by location, qualifying it, booking, then sending a reward all ran on people and a tangle of no-code triggers.
The brief was to own the whole path in code, from the ad to the text to the AI call to the clinic hand-off to the reward. Three things had to ship: the site that converts the click, the dashboard the operator watches, and the voice agent that runs the qualifying call.
I rebuilt the brand on a blue #447EF7 scale and moved every line of real copy off the old site. The offer centers an Apple Watch SE 3 rewards hook with a live deadline countdown. An insurance and clinic marquee, a branded link-preview card, a blue favicon set, and an accessibility pass round out the static build on Vercel.
On top of the site sit 6 SEO articles. The topics: dental check-ups, costs and the Canadian Dental Care Plan, choosing a dentist, how often to visit, dental anxiety, and teeth whitening. Each ships with search markup, hand-built on-brand diagrams, and AI-generated hero images.
#447EF7 scale, full copy migrationA Next.js 16 and React 19 dashboard on Supabase. It shows the lead funnel as 6 stages, with each lead's call history, recording and transcript links, reward status, and which Facebook ad it came from. A sortable, filterable table, CSV export, hourly auto-refresh, and manual reload give the operator one place to watch every lead move.
The operator (admin) sees everything, behind a secure login. Each clinic gets its own login showing only its leads: patient name, phone, email, and stage, with the ability to move a lead forward. Rewards, the text thread, and the activity log stay admin-only. The limits are enforced on the server, not just hidden in the UI: a clinic can only set the stages it owns, and the rest are rejected. An admin-only diagram shows how the phone and text channels run into the clinic and out to reward.
"Anna" qualifies leads on two channels at once. The voice agent uses Vapi for the call, Claude Haiku for the reasoning, Deepgram Nova-3 to turn speech into text, and ElevenLabs for the voice. The text qualifier runs the same script over SMS, driven by Gemini (gemini-2.5-flash-lite), 24/7. It keeps the conversation going on its own: anyone who replies by text gets followed up until hand-off. Both read and write one shared lead record, so neither re-asks what the other already learned, and the two never fall out of sync.
The behind-the-scenes pieces all run in code on Supabase: intake, a scheduled dialer, a scheduled text follow-up, a handler for call results, a handler for incoming texts, and a clinic-notify mailer. The right clinic is picked from the lead's postal code, and every status change is written to a running log that can't be edited after the fact. A missed call retries an hour later, then the next business day, then two days out, with text qualifying running alongside. After the last retry, calling stops. An incoming text still sends the lead straight to the clinic.
On a qualified lead, Anna transfers the live call to the clinic. If the front desk doesn't pick up, the clinic gets an automatic email (Resend) with the patient's details and the lead gets a "they'll call you back" text. After a completed visit, the patient gets an automatic text asking for a Google review of both the clinic and Orbit. Twilio carries the texts; Giftogram handles the rewards. Anna stays strictly on-script. The Canadian calling rules are built in: consent capture, a 9am-8pm ET calling window (seven days), live transfer only when the clinic front desk is staffed (Mon-Fri 12-4pm ET), and STOP handling.
The flow, start to finish: Facebook lead ad to instant text to AI call (text qualifying in parallel) to live clinic hand-off to reward and reviews.
One rule held across all three: keep the automation in code, so it stays easy to debug, easy to test, and free of no-code lock-in. The site, the dashboard, and the voice agent all run on Vercel and Supabase.
Scope facts from the build, technical only. Business results are the client's to share. The site, dashboard, and voice agent are all live.
Every lead can be followed from the ad click to the reward. Clinic routing is automatic. The calling window and STOP handling run in code, not on a checklist.
Similar work: a funnel to track, a voice agent to build, no-code sprawl to move into code. Discuss the project →