HubSpot CRM Setup Specification

Owner: CMO (Elena Vasquez) Related ticket: CAS-32 Last updated: 2026-04-07


Overview

CascadeGuard uses HubSpot Free CRM for lead capture and nurturing. Leads enter via the “Try Me” free scan flow: the user submits a Dockerfile, receives a blurred summary, then exchanges their email to see the full CVE report. At that point their email (plus scan metadata) is captured in HubSpot.

This document defines the contact property schema and the email drip sequence.


Contact Property Schema

These custom properties must be created in HubSpot before the POST /api/leads engineering work (see CAS-32 subtask) can populate them.

Create via: HubSpot → Settings → Properties → Contact Properties → Create Property

Property Name (Internal)LabelTypeDescription
cg_scan_dateCascadeGuard Scan DateDateTimeWhen the scan was submitted
cg_scan_idCascadeGuard Scan IDSingle-line textUUID of the scan
cg_risk_levelScan Risk LevelDropdowncritical, high, medium, low
cg_vuln_criticalCritical CVEsNumberCount of critical-severity CVEs
cg_vuln_highHigh CVEsNumberCount of high-severity CVEs
cg_vuln_mediumMedium CVEsNumberCount of medium-severity CVEs
cg_vuln_totalTotal CVEsNumberTotal CVE count from scan
cg_fixable_countFixable CVEsNumberCVEs with a fix available
cg_exploit_known_countExploit Known (CISA KEV)NumberCVEs with known exploits
cg_packages_scannedPackages ScannedNumberTotal packages in the scanned image
cg_lead_sourceLead SourceSingle-line textAlways try-me-scan for this flow

Contact Lifecycle Stage

  • Set to Lead on create
  • Update to Marketing Qualified Lead if cg_risk_level is critical or high (these contacts have the highest pain and are closest to a product fit conversation)

Email Drip Sequence

Three-email sequence, triggered when a contact is enrolled (form submission event).

Email 1 — Immediate: Your Scan Results

Timing: Immediately on enroll Subject: Your CascadeGuard security scan — {{contact.cg_vuln_total}} CVEs found Personalisation: Pull cg_risk_level, cg_vuln_critical, cg_vuln_high, cg_vuln_total

Body outline:

Hi,

You just scanned your Dockerfile with CascadeGuard — here’s what we found:

[RISK BADGE: {risk_level}]

  • Critical: {cg_vuln_critical}
  • High: {cg_vuln_high}
  • Total CVEs: {cg_vuln_total}
  • Fixable: {cg_fixable_count} ({pct}% of total)

These vulnerabilities are in your base image, not your application code. They’ll keep accumulating until the base image is rebuilt.

[CTA: View the full CascadeGuard quickstart →]

Goal: Acknowledge the scan, reinforce the problem, introduce the product.


Email 2 — Day 2: The Cascade Problem

Timing: 2 days after enroll Subject: Why your base image is a ticking time bomb Personalisation: Adjust intro based on cg_risk_level

Body outline:

The CVEs in your scan results aren’t random. They’re in the base image your Dockerfile inherits — and every week you don’t rebuild, more accumulate.

We wrote about exactly this: [Why Your Dockerfile Is a Supply Chain Risk →]

The fix isn’t exotic. It’s automation: detect the base image changed, rebuild, sign the new image, ship it through your GitOps pipeline. CascadeGuard does this automatically.

[CTA: See how the loop works →] (links to GitHub README/demo)

Goal: Educate, deliver value, link to flagship article, reinforce product.


Email 3 — Day 5: From Scan to Fix

Timing: 5 days after enroll Subject: From scan to fix: closing the container security loop Personalisation: If cg_fixable_count > 0, mention that specifically

Body outline:

The scan showed you the problem. Here’s the fix.

CascadeGuard is open source. It monitors your base images, detects when upstream updates land (or when CVE thresholds are crossed), and triggers a signed rebuild through your existing ArgoCD + Kargo pipeline.

Setup takes under 30 minutes.

[If fixable > 0: You had {cg_fixable_count} fixable CVEs — those are gone the next time your image rebuilds with the patched base.]

[CTA: Run the CascadeGuard quickstart →] (https://github.com/cascadeguard/cascadeguard)

Goal: Convert to product trial / GitHub star / install.


Workflow Configuration in HubSpot

  1. Trigger: Contact is enrolled in workflow CascadeGuard Try-Me Flow
  2. Enrolment criteria: Contact has property cg_lead_source = try-me-scan
  3. Sequence:
    • Immediate → Send Email 1
    • Wait 2 days → Send Email 2
    • Wait 3 more days → Send Email 3
    • Wait 7 more days → Unenroll (no further automated contact)
  4. Re-enrolment: Allow re-enrolment if cg_scan_date is updated (user scans again)

Engineering Requirements

The POST /api/leads endpoint (Workers API) must:

  1. Accept: { email, scanId, riskLevel, vulnCritical, vulnHigh, vulnMedium, vulnTotal, fixableCount, exploitKnownCount, packagesScanned }
  2. Create/update a HubSpot contact via Private App API (HUBSPOT_PRIVATE_APP_TOKEN):
    • POST https://api.hubapi.com/crm/v3/objects/contacts (upsert by email)
    • Set all cg_* properties
    • Set cg_lead_source = try-me-scan
  3. Enrol the contact in the drip workflow (by workflow ID — obtain after workflow is created in HubSpot)
  4. Return 200 OK on success; log but don’t surface HubSpot errors to the frontend

The frontend (try-me/index.tsx) must update handleEmailUnlock to:

  • Call POST /api/leads with email + scan result summary data
  • Keep the existing HubSpot form submit as a fallback (or remove it once API is live)

See CAS-32 for the parent task.


Last updated: 2026-04-07 by Elena Vasquez (CMO)