Work / Lead & Sales / 01 · Home services & construction
Lead-to-Cash CRM for Three Contractors
Home services · New York · three companies, one owner · 2026
Delivered — figures counted directly from the exported workflow JSON
Stage Change Router, as exported
17 nodes · 16 connections · from the exported JSON
The shape of it
8 LEAD SOURCES
- Hosted form
- Website form
- Chat widget
- Tracked calls · CallRail
- Calendar bookings
- Facebook Lead Ads
- Social comments · 3 networks
- 8th intake, counted — not named in the write-up
ONE HUB
- normalise
- check for a recent duplicate
- mint a reference number
- grade Hot / Warm / Cold
- write the sheet
- email the customer
- text — only with explicit consent
- alert the sales team
STAGE DRIVES EVERYTHING
- webhook for human edits
- direct call for n8n’s own changes
6 AUTOMATION FAMILIES
- Estimate chaseDay 3 / 5 / 7 / 14 / 21 / 30
- Site-visit remindersanchored to the appointment
- Review & referral requestson completion, no gating
- Long-term nurturequiet leads, consent re-checked
- Offline conversionswon jobs → Google Ads · Meta
- Staff dashboardone per company, served from n8n
Drawn from the delivered README and the exported JSON. Endpoint paths, access details and credentials are deliberately absent — they belong in the client’s handover, not on a public page.
482 executing nodes, by type
34 if nodes, almost all of them consent and idempotency gates — the guards are a countable part of the system, not a claim about it. 552 objects on the canvas = 482 executing nodes + 70 sticky notes.
Staff dashboard, served straight from n8n
One dashboard per company, so nobody has to open the spreadsheet. Grades are Hot / Warm / Cold; the rules-based score stays in charge and the model writes its own column beside it.
The guards, and what each one prevents
- Idempotency is written before the action
Last Routed Stage is stamped before downstream actions fire: at-most-once, on purpose. A duplicate review email is worse than a missed automation.
- Race-safe lead IDs
Append first, let the sheet decide the row, then derive the reference from it. Never count the rows and add one — eight sources can land in the same second.
- Consent is an allowlist
The string “no” is truthy in JavaScript. A truthiness check would have opted in every customer who explicitly opted out.
- A texted STOP stops the emails too
Carrier-level blocking does nothing to an email sequence, so the opt-out is written back into the CRM.
- The AI drafts and never sends
A model that invents a price or a warranty in an email from the company is contractual exposure, not a UX bug.
- Money is chased only when it is owed
Reminders fire on explicit invoice statuses. A blank was never invoiced, and a blank is never chased.
Built with
- n8n · in 14 systems
- Google Sheets · in 6 systems
- Gmail · in 5 systems
- Google Ads · in 4 systems
- Meta · in 2 systems
- TwilioTwilio · in 3 systems
- CallRailCallRail · in 1 system