Integrations — GoHighLevel, Stripe & Email

CRM sync, payments and lead delivery are wired into every funnel out of the box. Add your secrets and you're live — no code changes.

GoHighLevel: checking… Stripe: checking… Email: checking…

GoHighLevel CRM Sync v3.1 · API v2

1 · Setup (5 minutes, works with your existing sub-account)

  1. In your GHL sub-account: Settings → Private Integrations → Create
  2. Scopes: contacts.write, contacts.readonly, opportunities.write, locations.readonly (+ workflows.readonly if enrolling)
  3. Copy the pit-… token + your Location ID (Settings → Business Profile)
  4. Local: add both to .dev.vars · Production:
    npx wrangler pages secret put GHL_API_KEY
    npx wrangler pages secret put GHL_LOCATION_ID
  5. Verify: open /api/ghl/statusconnected: true
Security: the PIT token lives server-side only (Cloudflare secret) — never in frontend code, never in a funnel URL, never in git.

2 · What happens on every lead — automatically

  • Contact upsert — dedupes by email/phone, so existing GHL contacts get updated, not duplicated
  • Auto-tagsrj-funnel + funnel-{slug} (e.g. funnel-mortgage) + offer tag + utm-{campaign} → trigger your existing GHL automations off these
  • Attribution note — full form details + UTM/gclid/fbclid/ttclid + source URL pinned to the contact
  • Opportunity (optional) — auto-created in your pipeline when GHL_PIPELINE_ID + GHL_STAGE_ID are set
  • Workflow enrollment (optional) — every lead dropped into the workflow in GHL_WORKFLOW_ID
  • Never breaks the funnel — if GHL is down or unconfigured, the lead is still accepted + emailed

Per-funnel custom tags: add ?ghlTag=client-acme,spring-promo to any funnel URL (or the Builder field) — those tags ride along on every lead from that link. Perfect for white-label client attribution.

Test the GHL sync from terminal (after secrets are set)

# 1. Connection check
curl https://funnels.rjbusinesssolutions.org/api/ghl/status

# 2. Fire a test lead — watch it land in GHL Contacts with tags rj-funnel + funnel-mortgage
curl -X POST https://funnels.rjbusinesssolutions.org/api/lead \
  -H "Content-Type: application/json" \
  -d '{"name":"GHL Test Lead","email":"[email protected]","phone":"+15055550100","_source":"/t/mortgage?utm_campaign=test","utm_campaign":"test"}'

Find your Pipeline / Stage / Workflow IDs (optional extras)

# Pipelines + stage IDs (uses your same PIT token)
curl -H "Authorization: Bearer pit-XXXX" -H "Version: 2021-07-28" \
  "https://services.leadconnectorhq.com/opportunities/pipelines?locationId=YOUR_LOCATION_ID"

# Workflows
curl -H "Authorization: Bearer pit-XXXX" -H "Version: 2021-07-28" \
  "https://services.leadconnectorhq.com/workflows/?locationId=YOUR_LOCATION_ID"

# Then:
npx wrangler pages secret put GHL_PIPELINE_ID
npx wrangler pages secret put GHL_STAGE_ID
npx wrangler pages secret put GHL_WORKFLOW_ID

Stripe Payments

1 · Setup (2 minutes)

  1. Grab your secret key from dashboard.stripe.com → Developers → API keys
  2. Local: copy .dev.vars.example.dev.vars, paste key
  3. Production: npx wrangler pages secret put STRIPE_SECRET_KEY
  4. Done. POST /api/checkout is live.
Security: the secret key lives server-side only — never in frontend code, never in git. Test with sk_test_ keys first.

2 · Use it — two modes

A — Existing Stripe Price ID (recommended)

fetch('/api/checkout', { method:'POST',
  headers:{'Content-Type':'application/json'},
  body: JSON.stringify({ priceId:'price_xxx' })
}).then(r=>r.json()).then(d=>location.href=d.url)

B — Ad-hoc price (one-time or subscription)

// One-time $1,997 setup
{ name:'DFY Social Growth — Setup', amount:199700 }
// $997/mo subscription
{ name:'DFY Social Growth — Monthly', amount:99700, interval:'month' }

Drop-in checkout button (paste into any funnel/page)

<button onclick="fetch('/api/checkout',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({name:'DFY Social Growth — Setup',amount:199700})}).then(r=>r.json()).then(d=>{if(d.url)location.href=d.url;else alert(d.error)})" style="background:linear-gradient(135deg,#2563eb,#0ea5e9);color:#fff;font-weight:700;padding:16px 40px;border-radius:16px;border:none;font-size:18px;cursor:pointer">Get Started — $1,997 →</button>

RJ 3-tier pricing wiring (Free / Pro / Enterprise pattern)

// Tier buttons — swap in your real Stripe Price IDs
const TIERS = {
  starter:    { priceId: 'price_STARTER_ID' },     // e.g. $497/mo
  pro:        { priceId: 'price_PRO_ID' },         // e.g. $997/mo  ← "Most Popular"
  enterprise: { priceId: 'price_ENTERPRISE_ID' }   // e.g. $2,497/mo
}
document.querySelectorAll('[data-tier]').forEach(btn => btn.addEventListener('click', async () => {
  const r = await fetch('/api/checkout', { method:'POST', headers:{'Content-Type':'application/json'},
    body: JSON.stringify(TIERS[btn.dataset.tier]) })
  const d = await r.json()
  if (d.url) location.href = d.url; else alert(d.error)
}))

Email / Lead Delivery (Resend)

1 · Setup (3 minutes)

  1. Free account at resend.com (3,000 emails/mo free)
  2. Verify your sending domain (or use [email protected] to test)
  3. Local: add RESEND_API_KEY + LEAD_NOTIFY_EMAIL to .dev.vars
  4. Production: npx wrangler pages secret put RESEND_API_KEY
Already wired: all 8 lead-capture funnels (real estate, coaching, law, home services, med spa, insurance, agency, tax) POST to /api/lead automatically. You get a branded RJ Blue lead email for every submission.

2 · How the funnel forms behave

  • Form fields auto-serialize to JSON + _source (page URL)
  • Button shows spinner → "✓ Submitted!" state
  • No API key yet? Lead still accepted (never breaks the funnel) — you just don't get the email until configured
  • TCPA consent checkboxes remain required on regulated verticals

GoHighLevel sync runs automatically alongside email (see the GHL section above) — or point a form at any external webhook via data-lead-form="https://your-webhook-url".

Test the lead API from terminal

curl -X POST https://YOUR-DOMAIN/api/lead \
  -H "Content-Type: application/json" \
  -d '{"name":"Test Lead","email":"[email protected]","phone":"(505) 555-0100","_source":"manual-test"}'

Add lead capture to ANY custom page

<form data-lead-form>
  <input name="name" placeholder="Full name" required>
  <input name="email" type="email" placeholder="Email" required>
  <input name="phone" type="tel" placeholder="Phone">
  <label><input type="checkbox" required> I agree to be contacted by phone/text/email. Consent not required to purchase.</label>
  <button type="submit">Send My Info →</button>
</form>
<script src="/static/app.js"></script>

Secrets Reference

SecretUsed byRequired forSet with
STRIPE_SECRET_KEY/api/checkoutPaymentswrangler pages secret put STRIPE_SECRET_KEY
RESEND_API_KEY/api/leadLead emailswrangler pages secret put RESEND_API_KEY
LEAD_NOTIFY_EMAIL/api/leadWhere leads land (default: [email protected])wrangler pages secret put LEAD_NOTIFY_EMAIL
LEAD_FROM_EMAIL/api/leadSender identity (verified domain)wrangler pages secret put LEAD_FROM_EMAIL
GHL_API_KEY/api/lead · /api/ghl/statusGHL contact sync (PIT token)wrangler pages secret put GHL_API_KEY
GHL_LOCATION_ID/api/leadYour sub-account locationwrangler pages secret put GHL_LOCATION_ID
GHL_PIPELINE_ID/api/leadAuto-opportunities (optional)wrangler pages secret put GHL_PIPELINE_ID
GHL_STAGE_ID/api/leadPipeline stage (with pipeline)wrangler pages secret put GHL_STAGE_ID
GHL_WORKFLOW_ID/api/leadWorkflow enrollment (optional)wrangler pages secret put GHL_WORKFLOW_ID