The difference between a tool operator and an architect: a state-of-the-art autonomous BDR, built for chaos.
An autonomous WhatsApp BDR that runs a full NEPQ sales conversation end to end — cold outreach to booked meeting, no human in the loop. Running in production.
- Built for the channel where ~99% of Brazilian business happens — even B2B. Competitors pay four BDRs to work WhatsApp by hand all day; as a solo founder, that time is the entire business.
- Took a solo agency from $0 to $30K MRR — hitting its monthly client-cohort cap with zero human prospecting.
- Optimization is continuous: it feeds on customer-intelligence data from real conversations, meetings, and signals.
- ~69% → 34% → 65–75% reply across versions · ~32% booking (v4) · ~2-min avg response
- Production-grade, not a demo: a 15-min kill-switch auto-suspends any WhatsApp instance whose ban rate crosses 5%; a global error handler logs every failure with Telegram alerts; real-time ban detection blocks sends on the spot; a SQL preflight gate checks instance health before every message.
There are hundreds of autonomous email SDRs. There are zero autonomous WhatsApp BDRs — and the reason is instructive.
Email outreach is the CLI era of sales: you type a command, you wait, the interface never surprises you. That's why it automates cleanly — hundreds of autonomous SDRs exist. WhatsApp is the conversation that answers back. Audio, images, a “quem é você?”, a partner who grabs the phone mid-thread — none of it scripted. The only bots that survive that today talk to warm leads, where the questions are predictable and an FAQ covers most of them. A cold BDR has no such luxury: no intent, no map, pure chaos. So the category didn't exist. And in a country where ~99% of business runs on WhatsApp, with competitors fielding four BDRs by hand, that missing category was the whole problem — and, solo, mine to solve alone.
Here's the part nobody wants to hear: in a cold thread, you have almost nothing. No intent, no context, a stranger who owes you zero seconds. So you stop guessing what they want — guessing is the amateur move — and you use the one thing the chaos can't take from you: their own words. The lead names a pain, and the agent doesn't paraphrase it. It quotes it back, verbatim. That's when the room changes. But it still doesn't get to pitch. It has to earn it — and “earn it” isn't a vibe, it's a condition in the code: the bridge to a meeting fires only when the pain is named and the desired outcome is projected (dor_nomeada AND desejo_projetado). No named pain, no bridge. The bot can't manufacture urgency it never heard. That single gate is the whole thesis — the line between a script that pushes and a conversation that qualifies itself.
(To be precise about what this is and isn't: I capture the signal and it shapes the copy at the point of generation. It's not a system that learns on its own. That part is still me.)
GTM Engineering, stripped of the hype, is still GTM — the intersection of marketing, sales, and product. So the first thing I built wasn't the plumbing; it was the conversation logic. Sales psychology, objection handling, real neuro-persuasion technique, translated into something a machine could run. The assumption underneath was the one everyone makes on this kind of work, and it felt airtight: if a bot could apply what a good human SDR already knows, how could it fail? I was very wrong.
What building this taught me the hard way is that you spend far more time designing for the imperfect case than the perfect one. The perfect reply — lead names the pain, asks for the call — needs almost no code. Two kinds of imperfection eat the months. There's the conversation: the voice note at 11pm, the “quem é você?”, the partner who grabs the phone mid-thread, the half-yes, the objection dressed as a question. And there's the system underneath it: silent failures that swallow an error without a trace, an API call that fires twice and double-messages a lead, race conditions, a connection that drops mid-send. A good share of the refactors were never about making the bot smarter — they were about the things that quietly broke. That gap is the entire distance between a demo and a system. It's also, concretely, why the first version ran on ~20 n8n nodes and the current one runs on ~90.
The motion starts before the lead ever replies. A cadence opens cold — and it opens with a question, not a pitch, because in a channel this personal a question is the only thing that earns a response. When the lead answers, that message hits a single webhook, and the first decision the system makes isn't what to say — it's who should say it. A router reads the lead's number and their conversation state (bdr_threads.nepq_state) and sends the thread down one of three paths: the cold BDR, the warm SDR, or silence, if they're already booked or closed. One door, deterministic triage.
On the BDR path, the conversation runs a four-stage NEPQ arc — ack_clarify → probe_dor → solution_awareness → ponte, three turns if it can, five at most. An LLM agent writes the reply, but it never runs alone: a deterministic layer sits in front and resolves the moves I can predict — a clean yes, a decision-maker check, a booking intent — with plain regex, so the model is only invoked when the conversation is genuinely ambiguous. That's the 20-to-90-nodes lesson in practice. Most of those nodes aren't intelligence; they're the handling of every imperfect path the intelligence shouldn't be trusted with. AI is a phenomenal partner when you know exactly the output you want — and a liability the moment you let it decide on its own.
The bridge is a guarded transition— it can't fire on empty desire. No named pain, no bridge; the agent can't manufacture urgency it never heard.
Everything that goes out clears a preflight gate written in SQL: no send unless the instance is healthy, the contact hasn't opted out, and the thread isn't flagged for reconciliation — blocked messages requeue, they don't disappear. And because leads talk the way people actually talk here, audio is transcribed and images are read by vision before the conversation logic ever sees them, so a voice note is just another turn.
1-- runs before every outbound message2select t.thread_id3 from bdr_threads t4 join wpp_instances i on i.id = t.instance_id5 where i.status in ('active','ramping') -- healthy6 and t.opted_out is false -- consent7 and t.compliance_ok is true8 and t.needs_reconcile is false; -- not mid-recovery9-- blocked → requeue(interval '7 days'), never dropped
Under it: n8n, Evolution API, Supabase, Twenty CRM, a classifier and a NEPQ agent on the LLM side, Cal.com and Google Calendar for booking, Reacher for email health, Telegram for ops. No Redis — state lives in Postgres and Twenty, and adding a cache nobody needed would've been architecture for its own sake.
None of that matters if the system quietly dies at 2am and I hear about it from a client. WhatsApp punishes automation harder than email — a number that sends too fast, or trips the wrong pattern, gets banned, and a banned number is dead weight. So the largest part of those ~90 nodes isn't conversation at all. It's the layer that keeps the thing alive without me watching it.
A monitor runs every 15 minutes and reads each number's health straight from the message log. If a number's ban rate crosses 5% — with a floor of 50 sends a day, so a quiet number can't trip it on noise — it suspends that number for 72 hours automatically, no human in the loop, and tells me after the fact. When a suspension expires, the number doesn't jump back to full volume; it ramps — 30, then 50, then 75, then 100 messages a day, three days per step — the way you'd warm a cold number by hand, except it never forgets.
Every workflow reports to a single error handler. When anything fails — a ban, a dropped Evolution call, an agent error — it gets fingerprinted by type and severity, written to a table with the execution URL so I can open the exact failure, and, if it's high or critical, it pings me on Telegram. Nothing fails silently. That one decision — make every error announce itself — is what turned “why did this lead go cold?” from a mystery into a link I click.
The sender has its own reflexes: if Evolution returns “disconnected” or “banned” mid-send, it flags the number and alerts me on the spot, independent of the monitor. And it doesn't type like a robot — it shows “typing…” for a beat scaled to the message length, then waits a random 7 to 15 seconds between messages, because the fastest way to get a number banned is to behave like software.
Some calls I keep for myself. A sentinel polls each number's connection state every few minutes, and when a connection looks degraded but not clearly dead, the system doesn't guess — it sends me two Telegram buttons, “suspend” or “keep,” and waits. Full autonomy where the signal is unambiguous; a human where it isn't.
This WhatsApp BDR was never a standalone bot — it's one channel in a two-channel cadence. The same leads are worked over email and WhatsApp in a coordinated sequence, which is why deliverability matters as much as conversation: Reacher verifies every address and watches domain health, so the email side stays out of spam while the WhatsApp side does the talking.
And every thread writes back to the CRM, because a conversation nobody can see later isn't an asset. When a lead enters, the system creates the Person, Company, and Opportunity in Twenty; it logs the NEPQ call briefing — likely pain, the hook, the discovery questions — so whoever takes the meeting walks in prepared; and it moves the record's state as the thread advances. CRM hygiene isn't an afterthought here — it's the difference between a bot that sends messages and a system a sales team could actually inherit.
One thing email never forces you to solve: WhatsApp is bound to a physical phone, not a login, so every number is its own island. All of them feed into a single Chatwoot inbox — one screen where a human can watch, or step into, any conversation across every instance. (That same unified history is what the agent reconciles from when a number drops.) And above it all sits the Apex dashboard: the control room for the BDR — instance health, ban status, what's in flight, what needs a human — so I'm never flying the system blind.
When a lead does say yes, a booking subroutine takes over. It proposes real slots — business hours, a two-hour lead time, a seven-day window — and either books the meeting on Cal.com straight from a plain-text confirmation or sends two links. A human approval step re-checks the slot against Google Calendar before the event is created, so it can never double-book me.
The version history is the least flattering and most useful part of this. The first version replied at nearly 69% and closed nothing — the conversation logic could open a door and had no idea what to do once it was inside. So I did what everyone does: I added. More rules, more branches, more “personalization.” Reply dropped to around 34%, and closing didn't move — over-engineering the perfect path only made the imperfect ones worse.
The turn came when I stopped adding and started listening. I began pulling the buyer's own language from everywhere my ICP already talks — the communities they live in, surveys, intake forms, on top of the real conversations, meetings, and objections I already had — and fed that verbatim back into the conversation logic. Mirror the lead's own words; gate the pitch on named pain. Reply climbed back to 65–75%, and the version that finally applied the original thesis booked around 32% of the leads that replied.
Now, capped operationally as a solo founder, I'm changing the premise on purpose. Instead of asking for a meeting cold, the current version leads with value — a lead magnet — to test whether reciprocity turns a cold lead into an engaged one, and lets me raise the ticket. That's the experiment running now.
None of this came clean, and the failures that taught me the most were the unglamorous, technical ones.
Every one of these now reports to a single error handler — because the first time a lead went cold for a reason I couldn't see, I decided nothing would ever fail silently again.
- v1
~69% reply · 0 close
Great at starting conversations, useless at finishing them. The logic could open a door and freeze inside it.
- v2–v3
~34% reply · ~10–12% close
I over-engineered the perfect path; the imperfect ones got worse.
- v4
65–75% reply · ~32% booking
The conversation intelligence from the original thesis, applied. Named base: 275 leads (179 confirmed-send to 206 including inbound-only).
- v5
the lead-magnet pivot · live now
Leading with value to turn cold into engaged and raise the ticket. Measured from day one.
and the constants underneath
- ~2-min average first response — seconds when the number is healthy; the average carries the instance drops from a live test.
- Progressive intent scoring— every reply, pain probe, and consequence raises the lead's score (+2 / +3 / +3), so the pipeline sorts itself.
- ~20 → ~90 nodes — the distance from demo to system, almost all of it spent on the imperfect paths.
- R$0 infra — built and run at cost, solo.
provenance
The BDR is almost a state-of-the-art of who I am — an intersection of a dozen disciplines.