EWA-HS
Marketing Opt-in → HubSpot — Backend Spec
Overview
When a user registers on the Academy and ticks "Send me updates about new courses, ESG regulatory changes, and EcoWorld Academy news", this consent must be synced to HubSpot as a GDPR-compliant email subscription.
Frontend (already done)
The registration form sends marketingOptIn: true | false in the RegistrationRequest payload to POST /register.
Backend — Registration API Pipeline
When the Registration API creates or updates a HubSpot contact (which already happens in the registration pipeline), it should additionally set the marketing subscription status.
Step 1: Create/update HubSpot contact
Endpoint: POST https://api.hubapi.com/crm/v3/objects/contacts
(or PATCH .../contacts/{contactId} if the contact already exists)
Properties to set:
{
"email": "jane@company.com",
"firstname": "Jane",
"lastname": "Pedersen",
"company": "Acme Corp",
"jobtitle": "Procurement Manager",
"country": "Norway",
"eco_number": "ECO-578-123-456-789"
}
eco_numberis a custom HubSpot property — create it in HubSpot Settings → Properties → Contact properties as a Single-line text field.
Step 2: Set email subscription status (GDPR-compliant)
Endpoint: POST https://api.hubapi.com/communication-preferences/v3/subscribe
Payload:
{
"emailAddress": "jane@company.com",
"subscriptionId": "<YOUR_SUBSCRIPTION_TYPE_ID>",
"legalBasis": "CONSENT_WITH_NOTICE",
"legalBasisExplanation": "User opted in during EcoWorld Academy course registration at academy.ecoworld.ai"
}
Only call this if marketingOptIn === true. If false, don't subscribe — don't unsubscribe either (they may already be subscribed via another channel).
Step 3: Find your Subscription Type ID
- In HubSpot, go to Settings → Marketing → Email → Subscription types
- Either use an existing subscription type (e.g. "Marketing Information") or create a new one:
- Name:
EcoWorld Academy Updates - Description: "New courses, ESG regulatory changes, and EcoWorld Academy news"
- Name:
- Get the subscription type ID from the URL or via the API:
GET https://api.hubapi.com/communication-preferences/v3/definitions
The response will include all subscription types with their IDs.
Step 4: Track consent metadata
For GDPR compliance, store the consent audit trail in your own database alongside the HubSpot sync:
INSERT INTO academy.consent_records (
user_id,
consent_type, -- 'marketing_email'
consented, -- true/false
consent_source, -- 'academy_registration'
consent_text, -- 'Send me updates about new courses, ESG regulatory changes, and EcoWorld Academy news'
ip_address,
user_agent,
consented_at -- timestamp
) VALUES (...);
Architecture Summary
Frontend Backend HubSpot
──────── ─────── ───────
POST /register 1. Create eco.entity
marketingOptIn: true 2. Generate E-C-O™ Number
email, name, etc. 3. Create academy.users
4. Create Cognito user
┌► 5. Create/update HubSpot contact ← Properties
│ 6. IF marketingOptIn:
│ Subscribe to email list ← Subscription
│ 7. Store consent record (local DB)
└► 8. Create Stripe session
9. Return checkoutUrl → redirect
API Permissions Required
The HubSpot private app token needs these scopes:
crm.objects.contacts.write— create/update contactscommunication_preferences.write— manage subscriptionscommunication_preferences.read— list subscription types
Notes
- Idempotent: If a returning user registers for another course, check if the contact already exists (by email) and update, don't duplicate.
- Unsubscribe: Always handled through HubSpot's built-in unsubscribe links in emails. Never programmatically unsubscribe a user just because
marketingOptInis false on a new registration — they may have opted in before. - Double opt-in: HubSpot supports optional double opt-in. If enabled, the subscribe API call will trigger a confirmation email. Recommended for GDPR but adds friction. Configure in HubSpot Settings → Marketing → Email → Subscription types.