📋 Workflow & Setup
📊 Live Dashboard

System architecture — how Option B is wired

LiveCosts owns
HubSpot CRM
Stays as system of record. Contacts, deals, history. Nothing changes for Marc or Ciaran's team. They work in HubSpot as normal.
Apex Emerald builds
Webhook Listener
HubSpot Private App on their account. Fires a payload to our Cloudflare Worker on any contact event: new contact, deal stage change, property update.
Apex Emerald builds
Cloudflare Worker
Receives and routes payloads. Classifies contact (new inbound vs. old lead vs. reactivation candidate). Triggers the right agent workflow.
Apex Emerald builds
GHL + Vapi/Retell
GoHighLevel runs the sequences. Vapi/Retell runs the voice. Outcomes (booked, callback, DNC) written back to HubSpot via REST API automatically.
LiveCosts sees
HubSpot (updated)
Every call outcome, deal stage update, and booked demo appears in HubSpot in real time. Ciaran's team never leaves their CRM. Plus this dashboard.
💡 The key point for Marc Nixon: LiveCosts never gives us access to run anything in their HubSpot. We create a Private App — a read/write connection they authorise once, control, and can revoke at any time. We get notified when things happen; we never touch their live data directly.

Step-by-step build — who does what and when

HS
LiveCosts creates a HubSpot Private App
→ Marc Nixon does this (15 min, no code)
In HubSpot: Settings → Integrations → Private Apps → Create. Name it "Apex Emerald Reactivation." Grant scopes: crm.objects.contacts.read, crm.objects.contacts.write, crm.objects.deals.write. Copy the Access Token and share it with Apex Emerald. That's it from Marc's side.
// Scopes Marc grants — minimum required
crm.objects.contacts.read // read contact data
crm.objects.contacts.write // write outcomes back
crm.objects.deals.write // update deal stage on booking
AE
Apex Emerald registers webhook subscriptions
→ Apex Emerald does this (same day)
Using the Private App, we subscribe to two event types via the HubSpot Webhooks API. These are the only two triggers we need for the database reactivation use case — and both are available on any HubSpot tier, free to enterprise.
// Event subscription 1 — segment pull trigger
object: contact
event: contact.propertyChange
property: hs_lead_status // fires when status tagged

// Event subscription 2 — new inbound (future use)
object: contact
event: contact.creation // fires on every new form sub

targetUrl: https://apex-emerald.workers.dev/hs-webhook
AE
Cloudflare Worker receives and classifies events
→ Apex Emerald builds this (2–3 days)
Every time HubSpot fires an event, our Worker receives the JSON payload, verifies the HubSpot signature (security), then classifies the contact into one of three buckets and routes accordingly. This is the brain of the system.
// Worker routing logic (simplified)
if (contact.createDate > 90_days_ago) {
→ route to INBOUND speed-to-lead agent
} else if (contact.lastContacted === null) {
→ route to REACTIVATION sequence
} else if (contact.dealStage === 'lost_timing') {
→ route to PRIORITY reactivation
} else {
→ log and skip (already worked)
}
GHL
Contact created in GHL + sequence triggered
→ Fully automated
Worker creates or updates the contact in GoHighLevel via GHL API. The correct campaign fires immediately based on the classification above. For reactivation contacts: voice call attempt within the next calling window (Mon–Fri 9am–6pm local time). For new inbound: call within 60 seconds.
// GHL contact payload
{
firstName: contact.firstname,
phone: contact.phone,
email: contact.email,
tags: ['livecosts-reactivation', contact.trade_type],
source: 'hubspot-webhook',
customField: { hs_contact_id: contact.id }
}
📞
Voice agent runs the call
→ Fully automated · Vapi or Retell
AI voice agent places the call. Opens with EU AI Act disclosure. Runs the qualification + booking script. Three possible outcomes handled live on the call: demo booked (calendar API), callback scheduled, or not interested (DNC flagged). No human involved at any stage.
HS
Outcomes written back to HubSpot automatically
→ Apex Emerald's worker handles this
Immediately after every call, our system patches the contact in HubSpot via the REST API. No manual logging. No CSV imports. Ciaran and Marc see everything in their CRM in real time — exactly where they're used to looking.
// PATCH to HubSpot after call — example: demo booked
PATCH /crm/v3/objects/contacts/{hs_contact_id}
{
hs_lead_status: "IN_PROGRESS",
lifecyclestage: "opportunity",
notes_last_contacted: "2026-06-14",
custom.reactivation_outcome: "demo_booked",
custom.demo_date: "2026-06-17T10:00:00Z",
custom.demo_with: "Ciaran Brennan"
}
📅
Demo appears in Ciaran's calendar automatically
→ Fully automated · Cal.com or HubSpot Meetings API
When the agent books a demo, it writes to Ciaran's calendar directly via Cal.com API (or HubSpot Meetings if they use that). Ciaran gets a standard calendar invite. The contact gets a confirmation by email. No admin required. The deal in HubSpot is moved to "Demo Booked" stage simultaneously.

What LiveCosts does vs what Apex Emerald does

LiveCosts team (Marc Nixon) — one-time setup

1.Create HubSpot Private App and share the Access Token with Apex (15 min)
2.Confirm which HubSpot contact properties to use for segmentation (e.g. lost_reason, lead_source, create_date) — quick call with Apex, 30 min
3.Add a HubSpot contact list filter that tags old unconverted leads as "Reactivation Candidate" — triggers the campaign automatically
4.Share Ciaran's demo calendar link so agent can book directly
Total time required from LiveCosts team: ~1 hour, one-time

Apex Emerald — we handle everything else

Build and deploy the HubSpot Private App webhook listener
Build the Cloudflare Worker routing and classification logic
Build and train the construction-fluent voice agent script
Build GHL sequences (voice → WhatsApp → email) per segment
Build HubSpot outcome write-back (PATCH on call completion)
Build and host this live dashboard
Monitor, maintain, and optimise the agent monthly
Build time: 10–14 days to first segment live · Full system live in 3 weeks

Option A (CSV) vs Option B (API) — when to use each

📄

Option A — CSV Pilot

Recommended to start

✓ No API access needed from LiveCosts
✓ Running in days not weeks
✓ Low commitment — test before full build
✓ Apex controls everything — clean proof of concept
✗ Manual import/export — not automated
✗ Outcomes don't auto-write to HubSpot
✗ Can't react to live events (new leads, deal changes)

Option B — Live API Integration

The full product

✓ Fully automated — zero manual steps once live
✓ HubSpot stays the source of truth
✓ Outcomes write back to HubSpot in real time
✓ Scales to full database without re-importing
✓ Can handle new inbound AND reactivation simultaneously
~ Requires Marc to create Private App (1 hour)
~ 2–3 week build time
💡 Recommended pitch: Start with Option A (CSV pilot, 350 contacts, prove the concept in 30 days). If results are good — and they will be — propose Option B as the natural next step. You earn the API access by proving ROI first. No one feels pressure, and you have data to justify the full build.

Database Reactivation

4,280 dormant contacts · HubSpot live sync · Running 47 days

Live — auto-updating
HubSpot connected
In Scope
4,280
Pulled from HubSpot
3,041 contacted so far
Calls Made
3,187
Across all segments
↑ 94 today
Connected
1,182
37.1% connect rate
↑ above benchmark
Demos Booked
183
4.3% of total in scope
↑ 6 today
Est. Pipeline Added
€54k
30% trial conversion assumed
From dormant leads
Demos Booked — Weekly
47 days running · Option B auto-scales as HubSpot tags contacts
11
W1
18
W2
24
W3
31
W4
29
W5
28
W6
42
W7↑
By Segment
HubSpot lost_reason tagging
Timing / Not ready
89
48%
No response
52
28%
Price / Budget
27
15%
Unknown / Untagged
15
8%
HubSpot Sync
Live write-backs today
Deal stage updates 94
Contact notes added 94
Demos auto-booked 6
DNC tags applied 12
Webhook errors 0
Last sync: 4 seconds ago ✓
Active Segments — pulled from HubSpot
Auto-updated as contacts are tagged in HubSpot
🎯 Priority — Timing segment
Lost reason: "not ready" · Created 2021–2022 · Xero/QBO
1,240
89 demos ✓
📬 No response segment
Submitted form · never replied · phone present
1,890
52 demos ✓
💰 Budget segment
Lost reason: "too expensive" · Retargeted with new pricing
680
27 demos ✓
+ Untagged contacts
Awaiting HubSpot classification from Marc's team
470
pending
Live Event Feed
Real-time webhook events
📅
Liam Connors · Plumbing, Mayo
Demo booked Thu 11am · HubSpot deal updated ✓
2 min ago · via webhook
📞
Sarah Burke · General, Clare
Callback Fri — noted in HubSpot contact
9 min ago · via webhook
📅
Ronan Daly · Electrical, Cork
Demo booked Wed 2pm · deal stage: Demo Booked
17 min ago · via webhook
📵
Karen Healy · HVAC, Kildare
No answer × 3 · WhatsApp sent · email queued
24 min ago
🔔
HubSpot → new contact tagged
"Reactivation Candidate" tag applied by Marc — 14 new contacts added to queue
31 min ago · webhook trigger
Recent Contacts — HubSpot Synced
All outcomes written back to HubSpot automatically
Booked (183) Callback (341) DNC (198)
ContactTradeSegmentAccountingOutcomeHubSpot updated
Liam Connors
Mayo, IE
PlumbingTimingXeroDemo Thu 11am2 min ago
Ronan Daly
Cork, IE
ElectricalTimingXeroDemo Wed 2pm17 min ago
Sarah Burke
Clare, IE
GeneralNo responseQuickBooksCallback Fri9 min ago
Karen Healy
Kildare, IE
HVACNo responseXeroNo Answer × 324 min ago
Mark O'Sullivan
Kerry, IE
CivilBudgetSageDemo Mon 9am1hr ago
Aoife Byrne
Wicklow, IE
Fit-outUntaggedXeroIn sequence2hr ago