# Cello HubSpot Integration

**Last Updated:** 2026-02-23

## Overview

This document describes how Cello referral parameters (`ucc`, `celloN`, `utm_medium`) are captured and mapped to HubSpot contact properties for proper attribution of referral signups (e.g. Tobias Kuhn, Lukas).

## Cello URL Structure

Cello links redirect to the workspace signup flow with parameters in the URL:

```
https://workspace.ordio.com/join?productId=www.ordio.com&utm_medium=cello%20kwk&ucc=hmuxRycYDRX&celloN=THVrYXM#/create/email
```

### Parameters

| Parameter   | Description                                      | Example      |
| ---------- | ------------------------------------------------ | ------------ |
| `ucc`      | Cello Unique Contact Code (referrer's code)      | `hmuxRycYDRX` |
| `celloN`   | Base64-encoded referrer name                     | `THVrYXM` (= "Lukas") |
| `utm_medium` | Lead source attribution (e.g. cello kwk)     | `cello kwk`  |

## HubSpot Property Mapping

### Contact vs Company Properties

| Object  | Internal Name              | Source                    | Notes                                      |
| ------- | -------------------------- | ------------------------- | ------------------------------------------ |
| Contact | `cello_referral_ucc__c`    | `ucc` URL parameter       | Cello form                                 |
| Contact | `own_cello_ucc__c`         | —                         | Empty for new signups; set when referrer   |
| Contact | `sign_up_type__c`          | Code (fixed: "cello_einladung") | Reporting; never use `sign_up_type` (no `__c`) |
| Contact | `firstname`, `lastname`    | Not sent                  | HubSpot uses full email as default display |
| Contact | `cello_referral__c`        | Decoded `celloN`          | Cello referrer name (Contact property)     |
| Company | `cello_referral_ucc`       | `ucc`                     | Company-level attribution                  |
| Company | `own_cello_ucc`            | —                         | Company-level                             |

**Important:** Never use referrer name (`cello_referral__c`) for Contact firstname/lastname. The contact is the invitee, not the referrer. Code does not send firstname/lastname; HubSpot uses full email as default contact display.

**sign_up_type error:** Use `sign_up_type__c` only. The property `sign_up_type` (without `__c`) does not exist on Contact and causes "isn't a Contact property" errors.

**Verify internal names** in HubSpot Settings > Properties > Contact properties before deployment.

## Architecture: Two Signup Paths

1. **Workspace flow (primary):** Cello links redirect to `workspace.ordio.com/join`. The workspace app (separate codebase) must extract `ucc`, `celloN`, `utm_medium` and map them to HubSpot when creating contacts.

2. **Landing page flow:** When users land on `ordio.com` with Cello params (e.g. from a link that goes to ordio.com first), the landing page captures and forwards them to HubSpot and to the workspace redirect.

## Cello Referral Landing Page (`/einladung`)

A dedicated landing page at `https://www.ordio.com/einladung` for Cello referral traffic.

- **File:** `v2/pages/cello_einladung.php`
- **Cello Attribution:** Script loads async; captures `ucc`, `celloN`, `productId` from URL
- **Form:** Uses `include_email_form.php` with `$emailFormCello = true` – submits to dedicated **Cello form** (GUID `a47cfeb7-4d00-4a76-971d-23a82739fb15`) with `leadsource` preset to "cello affiliate"
- **Personalization:** `getReferrerName()` updates hero headline when referrer name is available
- **Redirect:** Form preserves `ucc`, `celloN`, UTM params when redirecting to workspace

**Cello Portal configuration (post-deployment):** Log into [Cello Portal](https://portal.cello.so) → Setup → New User Experience → Custom landing page URL → `https://www.ordio.com/einladung`

See [CELLO_LANDING_PAGE.md](./CELLO_LANDING_PAGE.md) for full setup, testing, and production checklist.

## Landing Page Implementation (Technical)

### 1. Cello Helper (`v2/config/cello-hubspot-mapping.php`)

- `extractCelloParamsFromUrl($pageUrl)` – returns `[ucc, celloN]` from query string
- `decodeCelloReferrerName($celloN)` – base64 decode for referrer name
- Constants: `HUBSPOT_PROPERTY_CELLO_REFERRER_NAME`, `HUBSPOT_PROPERTY_CELLO_REFERRER_UCC`, `HUBSPOT_PROPERTY_OWN_CELLO_UCC`

### 2. UTM Tracking (`v2/js/utm-tracking.js`)

- Loaded via `head.php` on `/einladung`
- Extracts `ucc`, `celloN`, and UTM params from URL
- Stores in cookies and `window.utmTracking`
- `getUTMDataForAPI()` returns: `utm_source`, `utm_medium`, `utm_campaign`, `utm_term`, `utm_content`, `ucc`, `celloN`, `productId`, `page_url`, `referrer`
- Form maps to HubSpot: `source__c`, `utm_medium__c`, `utm_campaign__c`, `utm_term__c`, `content__c`

### 3. HubSpot API Endpoints

All lead-capture endpoints extract Cello params (from input, cookies, or `page_url`) and send them to HubSpot when non-empty:

| Endpoint                     | File                         |
| ---------------------------- | ---------------------------- |
| Hero Email Form (client-side)| `v2/base/include_email_form.php` – Hero form for homepage/gastro; Cello form for /einladung |
| collect-lead                 | `v2/api/collect-lead.php`    |
| lead-capture                 | `v2/api/lead-capture.php`    |
| submit-template              | `v2/api/submit-template.php` |
| addon-request                | `v2/api/addon-request.php`   |
| export-workdays              | `v2/api/export-workdays.php` |
| shiftops-hubspot             | `v2/api/shiftops-hubspot.php`|
| webinar-registration         | `v2/api/webinar-registration.php` |
| payroll-webinar-registration | `v2/api/payroll-webinar-registration.php` |
| event-lead-capture           | `v2/api/event-lead-capture.php` |

### 4. Hero Email Form (`v2/base/include_email_form.php`)

- **Submission:** Client-side `fetch()` to HubSpot Forms API v3 public endpoint (no API key)
- **Form GUID:** Conditional – Cello form (`a47cfeb7-4d00-4a76-971d-23a82739fb15`) when `$emailFormCello` true; Hero form (`c1d24914-f2a2-4371-b12a-7217553f5897`) otherwise
- **Cello form payload:** `sign_up_type__c: "cello_einladung"`, `cello_referral_ucc__c`, `cello_referral__c`, `leadsource: "cello affiliate"`. No firstname/lastname (HubSpot uses full email as default). Never sends `sign_up_type` (invalid).
- **Redirect:** Only after HubSpot confirms success. On error, user sees message and form stays enabled.
- **Redirect URL:** Built from persisted `utmData` (cookies/`getUTMDataForAPI`) – survives UTM cleanup. Preserves `ucc`, `celloN`, `productId`, `email`, and UTM params: `https://workspace.ordio.com/join?ucc=...&celloN=...&productId=...&email=...#/create/email` – workspace should pre-fill the email field when `email` is present
- **Verification:** `php v2/scripts/hubspot/verify-cello-form.php` (Cello form); `php v2/scripts/hubspot/verify-hero-form-cello.php` (Hero form)

## Workspace Implementation Checklist

The workspace app at `workspace.ordio.com` (separate repository) must:

1. Extract `ucc`, `celloN`, `productId`, `email`, `utm_medium` from the `/join` URL (landing page passes these in redirect)
2. **Pre-fill the email input** when `email` query parameter is present (landing page passes it after form submission)
3. Decode `celloN` (base64) to get referrer name
3. Map to HubSpot when creating/updating contacts:
   - `ucc` → Cello Referrer UCC
   - Decoded `celloN` → Cello Referrer Name
   - `utm_medium` → `utm_medium__c` (and ensure `leadsource` includes "cello kwk" or "cello affiliate" when applicable)
   - Own Cello UCC: leave empty for new signups

## utm_medium and leadsource

When `utm_medium` contains "cello" (e.g. `cello kwk`):

- Set `utm_medium__c`
- Set `leadsource` to a Cello value (e.g. "cello kwk" or "cello affiliate") – `hubspot_form_fields.json` lists these in the leadsource dropdown

## Validation

### Contact Properties Required

Form submissions only persist to Contact when field names match existing Contact properties. Create these in HubSpot (Settings > Properties > Contact properties) or run `php v2/scripts/hubspot/create-cello-contact-properties.php`:

| Internal Name | Label | Used By |
|---------------|-------|---------|
| `cello_referral_ucc__c` | Cello Referral UCC | Cello form |
| `cello_referral__c` | Cello Referral Name | Cello and Hero forms |
| `sign_up_type__c` | Sign Up Type | Hero, other forms |

See [HUBSPOT_FORM_FIELD_CONFIGURATION.md](../../guides/HUBSPOT_FORM_FIELD_CONFIGURATION.md) for the full "Create Contact Properties" section.

### HubSpot Cello Form Configuration (Manual)

In HubSpot Forms > Cello form (GUID `a47cfeb7-4d00-4a76-971d-23a82739fb15`):

1. **Add hidden fields** if missing: `sign_up_type__c`
2. **Remove** any field named `sign_up_type` (without `__c`) – use `sign_up_type__c` only
3. **Ensure** `cello_referral__c` is mapped to Contact property (not firstname/lastname)
4. **Verify** UTM fields: `source__c`, `utm_medium__c`, `utm_campaign__c`, `utm_term__c`, `content__c`

Run `php v2/scripts/hubspot/verify-cello-form.php` to check current form state.

**Manual: Add `cello_referral__c` if verify reports MISSING**

1. HubSpot > Marketing > Forms > Cello form (GUID `a47cfeb7-4d00-4a76-971d-23a82739fb15`) > Edit
2. Add field > Hidden field > Map to Contact property `cello_referral__c` (Cello Referral_Name)
3. Save

**Manual: Update property description for Sales**

1. HubSpot > Settings > Properties > Contact properties > `cello_referral__c`
2. Set **Description** to:  
   `Name of the person who referred this contact to Ordio. Use in emails: "Great to see that [Name] recommended Ordio to you." Visible to Sales – no Cello account needed.`
3. Save

### Form Field Verification

- **Cello form fields:** `php v2/scripts/hubspot/verify-cello-form.php` – confirms `cello_referral_ucc__c`, `cello_referral__c`, `leadsource`, UTM fields, and checks for `sign_up_type` (invalid)
- **Hero form fields:** `php v2/scripts/hubspot/verify-hero-form-cello.php` – confirms `cello_referral_ucc__c` and `cello_referral__c` exist on Hero form
- **Submission test:** `python3 scripts/cello/test-cello-hubspot-submission.py` – submits test lead to Cello form with Cello params
- **Landing page:** Submit on `/einladung?ucc=test123&celloN=THVrYXM`; verify HubSpot contact has Cello fields populated
- **Workspace:** Test Cello link signup; verify contact has Cello Referrer Name, Cello Referrer UCC, utm_medium
- **Hero form:** Land on ordio.com with Cello params, submit email; verify redirect only after success, and redirect URL includes `ucc`, `celloN`, `productId`
- **Workspace:** After redirect, workspace signup flow should receive `ucc`, `celloN`, `productId`, `email`, UTM params in URL. Verify email field is pre-filled when `email` param present; verify other params extracted and passed to HubSpot/backend.

## Sales Usage: Cello Referrer Name

The referrer name is stored in `cello_referral__c` (label: Cello Referral_Name). Sales can use it without a Cello account.

**Where to find it:** Contact record > Cello Referral_Name (in Salesforce Information group, or add to record layout).

**Email templates:** Use merge tag `{{contact.cello_referral__c}}` (or `{{cello_referral__c}}` depending on template context).

**Example copy:** "Great to see that {{contact.cello_referral__c}} recommended Ordio to you"

**Note:** Only populated when the contact came via a Cello referral link with `celloN` (base64-encoded referrer name) in the URL. Empty for non-referral signups.

## Risks and Dependencies

- **Workspace codebase:** Not in this repo; workspace team must implement for the primary Cello flow
- **HubSpot property names:** Must be verified; wrong names cause silent failures or API errors
- **Base64 edge cases:** Invalid base64 in `celloN` should not break contact creation; use safe decode with fallback to empty string

## Cello API and CDN Reference

| Resource | URL |
| -------- | --- |
| Cello Attribution (landing page) | `https://assets.cello.so/attribution/latest/cello-attribution.js` |
| Cello JS SDK (Referral Component) | `https://assets.cello.so/app/latest/cello.js` |
| Cello API Base URL | `https://api.cello.so/` |
| Product ID (production) | `www.ordio.com` |

Credentials (Product Secret, API accessKeyId/secretAccessKey) are stored in `v2/config/cello-config.php` (gitignored). See `cello-config.example.php` for structure.

## References

- [CELLO_LANDING_PAGE.md](./CELLO_LANDING_PAGE.md) – Landing page setup and credentials
- [HUBSPOT_FORM_FIELD_CONFIGURATION.md](../../guides/HUBSPOT_FORM_FIELD_CONFIGURATION.md) – Cello properties in field mapping table
