Setup guide

Zapier setup guide

# The Loyalty Tax Engine - Zapier setup guide

Zapier cannot import a Make blueprint. Build two Zaps by hand. This guide is click by click.

Australian English. Existing clients only. Default: the engine emails you, not the client. About forty-five minutes for a native CRM. Longer for HTTP / API paths.

## What you will have at the end

1. **Zap A — Watch.** Reads your CRM (or Google Sheet) and POSTs a canonical JSON payload to Zap B's Catch Hook.
2. **Zap B — Outreach.** Catch Hook → Filter (consent + gap) → ChatGPT → Gmail to you → (optional client Gmail, off) → Task → Note → Stamp.

Only the first step of Zap A and the last three steps of Zap B change per CRM. Do not rebuild the middle.

## Before you open Zapier

1. Create or map the fields in `05-templates/CRM-Field-Map.csv`.
2. Fill current rate, new-money rate, and gap bps. Default gate >= 25.
3. Open crm/CRM-INDEX.html in a browser. The HTML file for your CRM has Zapier’s first module and last three modules. This guide is the middle.
4. Add yourself as a test client with a gap at or above the threshold.
5. Have OpenAI (ChatGPT) and a real mailbox at your business domain connected in Zapier.

## Zap B first (you need the Catch Hook URL)

### B1. Trigger — Webhooks by Zapier → Catch Hook

1. Create Zap → **Webhooks by Zapier** → **Catch Hook**.
2. Copy the Custom Webhook URL. You will paste it into Zap A.
3. Click Continue. Leave it waiting for a sample (you will send one from Zap A later).

### B2. Filter — consent + gap + not opted out + weekly cool-off

Add **Filter** by Zapier. Only continue if:

- `email` exists
- `email_optout` (Text) does not exactly match `true`
- `existing_client` (Text) exactly matches `true`
- `tbt_loyalty_state` (Text) does not exactly match `opt_out`
- `tbt_loyalty_state` (Text) does not exactly match `touched` **OR** `tbt_last_loyalty_touch` is before 7 days ago (pick one rule and stick to it; simplest: state is `due` or `queued`)
- `tbt_loyalty_gap_bps` (Number) greater than or equal to `25`
- `tbt_current_rate` exists
- `tbt_new_money_rate` exists

### B3. ChatGPT — Conversation / Message

Model: `gpt-4o-mini` (or the closest ChatGPT action your Zapier plan exposes). Temperature low.

**System message** — paste the system rules from `03-skill/TBT-Loyalty-Tax-Conversation.SKILL.md` (the Rules section), plus:

Return ONLY a JSON object with keys: `broker_task_title`, `broker_task_body`, `broker_email_subject`, `broker_email_html`, `client_email_subject`, `client_email_html`, `crm_note`, `conversation_openers` (array of three short spoken lines).

Never invent a rate or saving. Never recommend switch/reprice/refinance. Restate only rates the payload supplied.

**User message** — map Catch Hook fields:

```
Draft the loyalty-tax pack for this existing client.
First name: {{first_name}}
Last name: {{last_name}}
Email: {{email}}
Mobile: {{mobile}}
Current rate: {{tbt_current_rate}}
New-money rate: {{tbt_new_money_rate}}
Gap bps: {{tbt_loyalty_gap_bps}}
Lender: {{lender}}
Product: {{product_name}}
CRM: {{crm}}
Contact id: {{contact_id}}
Last loyalty touch: {{tbt_last_loyalty_touch}}
Broker business name: {{business_name}}
Broker first name: {{broker_name}}
Broker email: {{broker_email}}
If a field is blank, leave it blank. Do not recommend a path. Remind the broker to run the file.
```

Parse the JSON output (Formatter → Utilities → Pick from JSON, or Code by Zapier).

### B4. Gmail — broker email (default on)

To: `{{broker_email}}`
Subject: mapped `broker_email_subject`
Body HTML: mapped `broker_email_html` plus the task title, body, and openers.
Add a footer line: `Default is notify you only. The client was not emailed.`

### B5. Gmail — client email (OFF)

Same Gmail app. To: `{{email}}`. Subject/body from the JSON.
Add a **Filter** before it: only continue if `auto_email_client` (Text) exactly matches `true`.
Every watch sends `false`. Leave it that way until the pre-launch checklist passes on yourself.

### B6–B8. Task, note, stamp

Swap these three for your CRM:

- **Task** — title `broker_task_title`, body `broker_task_body`, due today, linked to `contact_id`.
- **Note** — body `crm_note`.
- **Stamp** — set `tbt_loyalty_state` = `touched`, `tbt_last_loyalty_touch` = today.

Do not skip the stamp.

Name Zap B: `TBT Loyalty Tax · Outreach`. Turn it on.

## Zap A — Watch

### Native HubSpot example

1. Trigger: **HubSpot** → **New or Updated Contact** (or Scheduled → Search Contacts if you prefer a daily pull). Prefer a **Schedule by Zapier** (daily 09:00) + **HubSpot Find Contacts** filtered on `tbt_loyalty_gap_bps >= 25` and lifecycle customer when your plan allows.
2. Filter: email exists; lifecycle customer; state not `opt_out`; gap >= 25; last touch empty or older than 7 days.
3. Action: **Webhooks by Zapier** → **POST**. URL = Zap B Catch Hook.
4. Payload (JSON) — exact keys:

```json
{
"crm": "hubspot",
"contact_id": "{{id}}",
"first_name": "{{firstname}}",
"last_name": "{{lastname}}",
"email": "{{email}}",
"mobile": "{{mobilephone}}",
"tbt_current_rate": "{{tbt_current_rate}}",
"tbt_new_money_rate": "{{tbt_new_money_rate}}",
"tbt_loyalty_gap_bps": "{{tbt_loyalty_gap_bps}}",
"lender": "{{lender}}",
"product_name": "{{loan_product}}",
"existing_client": "true",
"email_optout": "{{hs_email_optout}}",
"tbt_loyalty_state": "{{tbt_loyalty_state}}",
"tbt_last_loyalty_touch": "{{tbt_last_loyalty_touch}}",
"broker_owner": "{{hubspot_owner_id}}",
"broker_email": "[YOUR BROKER EMAIL]",
"broker_name": "[YOUR FIRST NAME]",
"business_name": "[YOUR BUSINESS NAME]",
"auto_email_client": "false"
}
```

Replace the three bracketed placeholders. Leave `auto_email_client` as `false`.

### Salesforce / Pipedrive / Zoho

Same shape. Swap the trigger for that CRM's search / schedule pull. Map field names from `CRM-Field-Map.csv`. Pipedrive: paste custom-field hashes.

### Google Sheets bridge

Schedule daily → **Google Sheets Lookup Spreadsheet Rows** (or New Spreadsheet Row if you append). Filter existing_client TRUE, gap >= 25, state not opt_out. POST the same canonical keys. Set `crm` from `source_crm` or `google_sheets_bridge`.

### API CRMs

HTTP Request to search, then POST canonical payload. See `02-notes.md`. Or use the sheet until access is granted.

Name Zap A: `TBT Loyalty Tax · Watch · [CRM]`. Turn it on after Zap B has a sample.

## Test on yourself

1. Push your own test contact through Zap A.
2. Confirm Zap B runs. You get the broker email. No client email.
3. Confirm task, note, stamp.
4. Run again the same day — must not draft again.
5. Set `opt_out` — must not draft.

## Desk context (broker only)

35 new-money cuts since 1 June · 52 variables below 6% (late Aug 2026 Broker Times hike-flip desk angle). Broker context only. Not client copy.

## Important

This is an implementation toolkit. It is not financial, legal or compliance advice. The AI drafts. You decide.

Implementation toolkit. Not financial, legal or compliance advice. $99 AUD one-time. No strikethrough.