The result in one sentence
The lead who used to message on WhatsApp and wait hours for a reply is now greeted instantly, answers the right questions, receives the proposal as a PDF, and only then does the business owner step in to close.
- Client: my own product, for small and mid-sized businesses that sell over WhatsApp (clinics, service providers, local retail)
- My role: product, UX, frontend, backend, automations, landing page and operations
- Timeline: working MVP with dashboard, bot, embeddable form and landing page
- Key result: the first conversation happens on its own, 24/7, and the human receives an already qualified lead
- Two planes, each with one owner: Next.js is the control plane (login, number connection, dashboard); n8n is the automation plane (the messages). Both read the same source of truth in Supabase.
- Secrets never travel: only the instance identifier moves between systems. Each client's WhatsApp token lives in a table that neither the browser nor the user can read, only the server.
- One client, one number, provisioned: instead of a self-serve signup full of edge cases, onboarding is a script that creates the user, the WhatsApp instance, the links and the webhooks in one go. Less surface to break early on.
- A human conversation, not a form in a chat: a greeting with the lead's name, one question at a time, a questionnaire that can be switched off, and a one-click handoff for a human to take over.
- An immediate reply, 24/7, for every lead arriving through WhatsApp or the website
- The owner gets a WhatsApp alert only when the lead has finished and is ready to close
- Every lead organized in one dashboard, with source, answers and full conversation
- A portable lead base: in and out through CSV, no lock-in
- Its own Next.js landing page, with copy and visual system consistent with the product
The context
For many small businesses in Brazil, WhatsApp is the store. But the owner works alone or with a lean team, is busy when the message arrives and repeats the same questions all day. Whoever replies three hours later has already lost the customer to whoever replied in three minutes.
The problem
A missed message is lost revenue, and market solutions fall into two extremes: generic chatbots that feel robotic and push customers away, or customer service platforms far too complex for someone who just wants to stop losing leads. Website forms also ended up in an inbox nobody checked in time.
The approach
The solution
Connected in minutes. The client scans a QR code and the number is connected. The dashboard shows status, the paired number, the last connection and the last drop.
Visual automation. A vertical flow shows the lead's path: trigger, greeting, identification, questions, proposal and notification. The owner edits the copy, turns the questionnaire on or off and uploads the proposal PDF, which is sent automatically at the end.
A form for the website. The dashboard generates an embed code; whoever fills in the form on the client's site lands straight in the automated WhatsApp conversation. It replaced form plugins and paid integrations.
Leads and conversations. A lead table with source (form, WhatsApp or imported), CSV import and export with column mapping and phone-based deduplication, the full history of each conversation and a banner to turn the bot off for that contact and take over.
Under the hood
Next.js 16 (App Router, Server Actions) with Tailwind v4, Supabase (Auth, Postgres with RLS, Storage) and n8n with three workflows: form intake, lead replies and a log of every message. The WhatsApp provider is an API with one instance per client. Security definer RPCs granted only to the service role resolve the instance by slug or token. The public form has a honeypot, per-IP rate limiting, mandatory LGPD consent, and answers the same way for unknown slugs so clients cannot be enumerated. Security headers are mutually exclusive: only the form route can be embedded in an iframe; dashboard, login and API block clickjacking. Brazilian phone numbers are matched with and without the ninth digit, and n8n HTTP nodes retry so a network blip does not drop a conversation.
Results
What I take from this project
The most expensive bugs came from the edges nobody draws: a node that does not fire when a lookup comes back empty, the ninth digit of Brazilian mobile numbers, a duplicated header that breaks the iframe. Documenting each one the moment it shows up became part of the product.

