CRM 02 · HubSpot · Native

HubSpot. The default modules.

The HubSpot watch already uses Search Contacts. Create the five Contact properties before you import or those modules show as invalid. Type the internal name yourself. Do not let HubSpot rewrite it to tbt_current_rate__1.

Nativev1.0Five TBT fieldsGap default 25 bps$99 AUD once

← All 12 CRMs · Make guide · Zapier guide

Connection type: Native. OAuth to the HubSpot portal that holds the settled book. Re-use this connection on the task, note and stamp modules.

Settings → Data Management → Properties → Create property → object type Contact. Existing-client gate: the watch maps lifecyclestage = customer to existing_client: true. If you use another stage for settled clients, change that filter.

Do not write campaign state to a stock HubSpot property

State belongs in tbt_loyalty_state. Anything human-readable belongs in a Note. Do not dump the draft into HubSpot’s message field.

Fields for this CRM

Create the ones marked YES. Map the ones you already store. Do not invent a second current-rate field.

PurposeCanonicalThis CRMRequiredCreate?
Contact IDcontact_idhs_object_idYesNo
First namefirst_namefirstnameYesNo
Last namelast_namelastnameNoNo
EmailemailemailYesNo
MobilemobilemobilephoneRecommendedNo
Current ratetbt_current_ratetbt_current_rateYesMap or create
New-money ratetbt_new_money_ratetbt_new_money_rateYesYES - create or maintain
Loyalty gap (bps)tbt_loyalty_gap_bpstbt_loyalty_gap_bpsYesYES - create / compute
LenderlenderlenderRecommendedNo
Product nameproduct_nameloan_productRecommendedNo
Existing client flagexisting_clientlifecyclestage (must be customer) or tbt_existing_clientYesMap
Email opt-outemail_optouths_email_optoutYesNo
Loyalty statetbt_loyalty_statetbt_loyalty_stateYesYES - create this
Last loyalty touchtbt_last_loyalty_touchtbt_last_loyalty_touchYesYES - create this
Broker ownerbroker_ownerhubspot_owner_idRecommendedNo
Broker emailbroker_emailset in watch mapperYesSet in the watch

Full translation and notes: 05-templates/CRM-Field-Map.csv. Gap is in basis points. Example: current 6.40 and new-money 5.90 is a 50 bps gap. Default watch threshold is 25 bps.

Make — watch file to import

Import 02-make-blueprints/01-TBT-Loyalty-Tax-Watch-HubSpot.blueprint.json.

Import this file. Sign in to the portal that holds settled clients. Create the five properties first. Then import the outreach blueprint and paste its webhook URL into the watch.

Everyone also imports 02-make-blueprints/02-TBT-Loyalty-Tax-Outreach.blueprint.json. Import outreach first so you have the webhook URL. Walkthrough: MAKE-Setup-Guide.html.

Make — last-step swap

On the outreach scenario, modules 7, 8 and 9 are HTTP placeholders labelled SWAP. Replace them. The middle (consent, gap gate ≥ 25 bps, OpenAI, broker Gmail) does not change.

Outreach moduleSwap for
7 · Create the broker task — SWAPHubSpot → Create a Task. Title {{3.broker_task_title}}, body {{3.broker_task_body}}, associated with the contact.
8 · Write the CRM note — SWAPHubSpot → Create a Note (or Engagement note) on the contact. Body {{3.crm_note}}.
9 · Stamp loyalty touch — SWAPHubSpot → Update a Contact. Set tbt_loyalty_state = touched and tbt_last_loyalty_touch = today. Do not skip.

Stamp body (use this CRM’s field names from the table):

{
  "tbt_loyalty_state": "touched",
  "tbt_last_loyalty_touch": "{{formatDate(now; \"YYYY-MM-DD\")}}"
}

Zapier — first module and last three

Zapier cannot import a Make blueprint. Build two Zaps by hand. Full click-path: ZAPIER-Setup-Guide.html. This page is the CRM-specific first and last steps only.

WhereWhat
Zap A · first moduleSchedule by Zapier (daily 09:00) + HubSpot Find Contacts, filtered on tbt_loyalty_gap_bps ≥ 25 and lifecycle stage Customer when your plan allows. Otherwise New or Updated Contact plus a Filter. Then Webhooks by Zapier → POST to Zap B. Map HubSpot internals from the table (firstname, email, hs_email_optout, hubspot_owner_id, the five tbt_* properties).
Zap B stepModule
B6 TaskHubSpot → Create Task. Title from broker_task_title, notes from broker_task_body, associated contact = contact_id.
B7 NoteHubSpot → Create Engagement (Note) on that contact. Body from crm_note.
B8 StampHubSpot → Update Contact. tbt_loyalty_state = touched, tbt_last_loyalty_touch = today.

Zap A then POSTs the canonical keys (see the field-map Canonical column) to Zap B’s Catch Hook. Leave auto_email_client as false. Replace [YOUR BROKER EMAIL], [YOUR FIRST NAME], [YOUR BUSINESS NAME].

Fallback — Google Sheets bridge (01e)

If the HubSpot portal cannot be connected (wrong seat, missing Marketing/CRM scopes), export settled customers with rates and gap into the Google Sheet and import 01e the same week.

T Test on yourself before any live send

  1. Create yourself as a settled existing-client test record with a real email you read, a current variable rate, a new-money / retention reference, and tbt_loyalty_gap_bps at or above 25. State due or queued. Last touch empty.
  2. Run the watch (Make scenario 01, or Zap A) with a limit of 1, filtered to only this record.
  3. Confirm the broker email arrives. Confirm you did not get a client email. auto_email_client stays false.
  4. Confirm the broker task, the CRM note (or sheet write-back), and the stamp: state touched, last touch = today.
  5. Run again the same day. The engine must not draft you a second time. Then set state to opt_out and run again — must not draft.

If the stamp fails, stop. Fix it before anyone else is in the set. After the loop is proven on you, you may flip auto_email_client — not before. Read 04-compliance first.