Case study · CRM automation
A leaking CRM, turned intothe system it runs on.
An Australian registered training organisation had GoHighLevel, but leads landed with no owner, forecasts were inflated, and a broken follow-up had stranded students mid-application.
ClientRegistered training organisation, Australia
RoleAudit, architecture, and build
StackGoHighLevel, n8n, webhooks, REST API, Node.js
SHIPPING RECEIPT
Training provider
CRM auditdone
Round-robin lead ownersdone
Evidence chase rebuiltdone
Dashboard in GoHighLeveldone
Automations shipped12
Students unblocked26
SHIPPEDWhat the audit found
Counted, then fixed.
Every finding came with a number, so the fix list could be ranked by cost and risk.
| Finding | Count | Fix | Status |
|---|---|---|---|
| Custom fields duplicated as mirror copies | 27 | Merged, with tighter access on sensitive fields | done |
| Contacts stuck in unpublished workflows | ~244 | Surfaced and routed back into live workflows | done |
| Students stranded by a document chase with a bug | 26 | Chase rebuilt around a live checklist | done |
| New inquiries with no owner | all | Round-robin assignment on arrival | done |
| Ad spend in the marketing dashboard | · | Being wired in | partial |
The architecture
GoHighLevel is the front door. n8n runs the logic.
GoHighLevel
What the team sees and uses every dayContacts and custom fieldscrm
Pipelines and stagescrm
Calendars and bookingscrm
Two-way shared inboxcustom channel
Embedded marketing dashboardtoken-gated
n8n
The logic GoHighLevel can’t do nativelyTrue days-in-stage averagescalc
Live evidence checklist in each emailrender
Net profit and amount-due roll-upcalc
Self-refreshing integration tokensauth
Access-controlled Drive foldersstorage
The evidence chase
A follow-up that stops on its own.
Each email lists only what’s still missing. Press play to watch one example file fill up.
Student file
Photo IDreceived
Qualification certificatesreceived
Employment evidencereceived
Signed declarationreceived
To: Sam (example student)Subject: Your file is complete
File complete. The chase has stopped.
No more reminders go out, and the opportunity moves on by itself.
Under the hood
The check that ends the chase.
// What is still missing from this student’s file?
const required = $json.course.requiredDocuments;
const received = $json.contact.documents;
const missing = required.filter((d) => !received.includes(d));
return [{
json: { missing, complete: missing.length === 0 },
}];
n8n: evidence chase · code node
upload receivedget contactwhat’s missing?complete: stop chaseelse: email checklist
1The checklist is worked out per student, so every email lists only what is still missing.
2When complete is true, the chase stops on its own. The old one never stopped, which is how 26 students got stranded.
Simplified for reading. Client names and data removed.
A Sydney milliner