How the flow works
The AI bot owns the email side: watches the inbox, parses each enquiry, drafts the reply, then fires a single API call to a HubSpot workflow webhook trigger. The webhook enrolls the broker, creates a deal, and a second workflow sends the marketing reply.
Why a Make.com step exists: HubSpot's standard workflow actions can only set Text / Number / Boolean properties from a webhook. They cannot set Dropdown, Date, or Multiple-checkbox properties. So the bot sends those values into "Broker WF Helper" staging properties (single-line-text type, which the workflow can set), the reply email goes out immediately, and a Make.com scenario reads the staging text and back-fills the real typed properties (writing dropdown options straight through, converting dates, filtering multi-checkbox values). The email never waits on Make. The staging text stays on the deal as a permanent fallback.
Assumption: all broker emails come from contacts that already exist in HubSpot. Unknown senders are silently dropped by the workflow (no deal created). In parallel, every broker email continues to be forwarded to RWE's shared inbox / Slack (set up separately by Jacob — outside this flow) so the team has full visibility.
One external endpoint. Two HubSpot workflows. One Make.com back-fill scenario.
Broker sends email
broker-responses@runwayea.st
AI bot watches this inbox
Watch, parse, draft, POST — all in one system
- Read email: sender, domain, subject, body, Message-ID
- Parse enquiry: prospect name, prospect company, area, budget, move date, requirement size, other requirements
- Match against RWE offices → select top 3
- Draft the reply email body ("Hi there" → sign-off; HubSpot template wraps it with branded signature + one image)
- POST a single JSON payload to the HubSpot webhook trigger URL
POST single JSON payload to HubSpot webhook trigger
- Endpoint:
POST https://api.hubapi.com/automation/v4/webhook-triggers/6650005/hW4hjt7(production, updated 2026-06-17 — replaces the retireduc3IdQutrigger) - Payload includes contact and deal properties (see field spec spreadsheet for the full list)
Workflow event: "Broker AI Webhook"
- Contact-based webhook trigger (workflow automation v4)
- Identifies broker by
emailfield in payload - Workflow enrolls the matching broker contact
- All other payload fields (
area,budget,move_date,broker_ai_sales_email_reply, etc.) become available as workflow tokens for use in subsequent actions
Trigger: Broker AI Webhook event received
- Enrolled record = the broker contact identified by the webhook payload
Is this a broker? = Yes on the enrolled contact (only if not already set against the contact).
Deal name= e.g.{{webhook.firstname}} - Broker EnquiryPipeline= Sales Pipeline (hardcoded)Deal stage= Unqualified (hardcoded)Entry Point= Broker Enquiry (hardcoded)Automated?= Yes (hardcoded)- Text / Number fields → their real properties directly from webhook tokens
- Dropdown / Date / Multi-checkbox → their
… - Broker WF Helperstaging siblings (see staging table below)
prospect_* fields can be carried in the payload and unused for now, or excluded until phase 2.
Back-fill Dropdown / Date / Multi-checkbox from the staging text
- Runs independently of the email send — does not delay Workflow B
- Watch Deals → picks up the new broker deal and reads its
… - Broker WF Helperstaging values - Dropdowns (
location,type_of_membership, current-office product type, notice-served) → the bot sends the exact option name; Make writes it straight into the dropdown property - Date (
move_date) →parseDateconverts the text to a real date (no AI) - Multi-checkbox (
competitors_for_tours,current_office___provider) → split on;, drop any value not in the allowed options, rejoin - Update Deal → writes the real typed properties back onto the same deal
- If Make fails, the staging text remains as a fallback and the deal/email are unaffected
Trigger: Deal created where Entry Point = Broker Enquiry AND Automated? = Yes AND Broker AI sales email reply is known
- Enrolled record = the deal just created by Workflow A
{{deal.broker_ai_sales_email_reply}} in a plain-text-style template — body + branded signature + one image (matches the existing sequence email style, no chrome/headers/colour blocks). Audience filter: deal contacts with association label = Broker.
Broker receives the quote response
- Marketing email delivered, tracked by HubSpot
- Deal sits at
Unqualifiedin the Sales Pipeline for sales team follow-up - Broker contact associated to deal with label = Broker
- Full audit trail on the deal: AI reply body, Email Message ID, all parsed fields
Route deal for human handling
- Marketing email send fails inside Workflow B (bounce, template error, etc.)
- Notify deal owner / team Slack channel
- Raw email body still on the deal as backup
- Reviewer replies manually + logs in HubSpot
7 "Broker WF Helper" staging properties to create (for the Make parsing)
These 7 fields are complex types the workflow can't set directly. For each, create a single-line-text-type property named <Property> - Broker WF Helper the webhook writes into, then Make reads it and writes the real typed property. The - Broker WF Helper label makes these helper/staging fields obvious in the property list. Text / Number / Multi-line / Rich-text fields need no staging — they map straight from the webhook.
Each staging property is single-line-text type. The display label is shown in bold; the internal name below it is what the webhook and Make reference.
| Real property (target) | Type | Staging property to create (single-line-text type) | Make parsing |
|---|---|---|---|
move_date | Date | Move in date - Broker WF Helpermove_in_date__broker_wf_helper | parseDate (no AI) |
location | Dropdown | RWE Location Interested In - Broker WF Helperrwe_location_interested_in__broker_wf_helper | write straight to dropdown |
type_of_membership | Dropdown | Product Type - Broker WF Helperproduct_type__broker_wf_helper | write straight to dropdown |
current_office___product_type__dropdown_ | Dropdown | Current Office - Product Type - Broker WF Helpercurrent_office__product_type__broker_wf_helper | write straight to dropdown |
current_office___notice_served_to_provider | Dropdown | Current Office - Notice Served to Provider - Broker WF Helpercurrent_office__notice_served_to_provider__broker_wf_helper | write straight to dropdown |
current_office___provider | Multi-checkbox | Current Office - Provider - Broker WF Helpercurrent_office__provider__broker_wf_helper | split ; → filter to valid options |
competitors_for_tours | Multi-checkbox | Competitors for Tours - Broker WF Helpercompetitors_for_tours__broker_wf_helper | split ; → filter to valid options |
No staging needed (write direct from webhook): nature_of_business (Multi-line text), broker_ai_sales_email_reply (Rich text), and all Text / Number / Phone fields. The AI bot must JSON-escape newlines (\n) in the rich-text email body, and the multi-checkbox staging values must be sent semicolon-separated.
✓ Scenarios tested (demo portal, 3 June 2026)
Webhook trigger validated 13 May 2026. Make.com back-fill validated 3 June 2026.
| Scenario | Outcome | What it confirms |
|---|---|---|
| Full valid payload | All typed properties set: Product Type (Dropdown), Move-in date, Competitors (Multi-checkbox). Staging text retained. | The core back-fill works end to end. |
Multi-checkbox, invalid value (Mindspace) |
Invalid value dropped by the filter; the valid competitors still write. | The filter protects the multi-checkbox write. |
| Blank date + blank competitors (empty strings) | Those fields left blank, no error, everything else writes. | Empty values are safe, no guard needed. |
| Blank dropdown (blank product type) | Writes blank, the run continues, other fields still write. | A blank dropdown can't crash the run. |
Near-miss dropdown (Hot Desk vs Hotdesk) |
That dropdown left blank, no error, every other field writes. Staging text keeps the bad value visible. | Dropdowns fail safe (blank), so pass-through is safe for them. |
| Exact-match multi-checkbox + special characters | A non-exact value is dropped by the filter (no crash); exact matches (Us&Co, Work Life) write. Found a real quirk: one option's internal value has a double space (Uncommon (Uncommon)), so a single-space version is correctly dropped. |
The filter's allowed-list and the bot must use HubSpot's exact internal values. |
Apostrophe in a dropdown option (Don't know) |
A straight apostrophe didn't match HubSpot's option, so the dropdown blanked gracefully (no crash). | The bot must send the option's exact apostrophe character. |
Phone number (international, e.g. +61412216133) |
The staging text keeps the +, but Make's "Parse Custom Fields" reads +61… as a number and drops the +, so HubSpot's Phone-number validation (requires a leading + and country code) rejected it. Fixed by re-adding the + in the Make mapping: +{{phone_number___broker_wf_helper}}. A plain single-line-text property avoids the issue entirely (keeps the + as entered). |
Phone needs the + preserved. Either use a text property, or re-prepend the + in Make when using the Phone-number type with validation on. |
| Partial data / missing keys | Deal created with the missing field left blank. | Graceful skip on absent keys. |
| Unknown broker email | HubSpot returns 202, the workflow silently drops the event. | Expected, RWE assumes all broker emails already exist in HubSpot. |
Still to test / confirm
- Other dropdowns — only Product Type wired so far;
location,type_of_membership, current-office product type, notice-served each need mapping (straight pass-through, same as Product Type) - Second multi-checkbox —
current_office___providernot yet wired (same Iterator + filter pattern as competitors) - Phone number field — confirm a Phone-number-type property keeps the
+and full international format (writes directly from the webhook, no Make needed) - Full production payload — all fields populated, end to end
- Live bot POST — tested via Hoppscotch by hand so far, not yet the real AI bot
- Email send — confirm Workflow B sends the reply, reading staging/webhook values (never the initially-blank typed properties)
- Duplicate / repeat enquiries — same broker firing twice; no duplicate deals/contacts
- Retry behaviour — bot retry if HubSpot returns non-202; Make error handling on a failed Update Deal
- Prospect → Deal association — phase 2 scope
What AI dev needs from us
- Webhook trigger URL from the production workflow (one URL, locked in once)
- Field mapping spec — final list of JSON keys the AI bot will POST (matches HubSpot internal property names where applicable)
- Email reply must be HTML, not plain text —
broker_ai_sales_email_replyis a Rich-text property that Workflow B sends as the outgoing email. The bot should format paragraphs as<p>…</p>(or<br>for line breaks), JSON-escaped, not raw\n— plain newlines collapse when the email actually sends, running the paragraphs together. Build the JSON with a real encoder (never hand-assemble) so quotes/newlines escape correctly.
✓ Webhook trigger mapping — all 29 fields tested & saving (2026-06-05)
Every field in the production payload now maps and saves on HubSpot's "When a webhook is received" trigger. Hard-won gotchas worth keeping:
- Cause: either the field names were too similar, or HubSpot had a block on that specific field. Each field that failed had a near-identical existing property of a different type (a number, or another
__broker_wf_helper). HubSpot's webhook mapping either conflated the two, or simply refused that field — we couldn't pin down which. Either way the whole mapping save fails with a generic "There was a problem creating your webhook event." Not your data; a HubSpot-side limitation. - Fix = rename the colliding field to a short, distinct single-line-text property. Three fields hit this and were renamed:
current_office__notice_served_to_provider__broker_wf_helper→current_office__notice__broker_wf_helper(collided withcurrent_office__provider…— the two couldn't coexist)original__budget→original_budget(collided with thebudgetnumber property)original__what_size_office_do_they_need_in_desks→original_number_of_desks(collided withnumber_of_desksnumber twins)
- Data types: map everything as string except
fixed_term,amount,size_of_the_team(number). Phone (prospect_contact_phone_number) = string (the leading+breaks it as number/phone type). - Avoid number/boolean/date-looking values in text fields where possible (HubSpot infers type from the sample value). Send
8 to 10 desksnot8-10;GBP 12000not£12,000; the£symbol also caused parse issues. - POST 202 ≠ saved. A 202 means HubSpot received the payload; it does not mean the field mapping saved. Always complete Map + Save to confirm.
- Working payload:
Business Information/rwe-2026-5th-jun-broker-webhook-FINAL-WORKING-payload.json
Email size — tested, safe
Latest version of the marketing email (plain-text body + branded signature with attached image):
| Part | Size |
|---|---|
| HTML body (plain-text style) | 20 KB |
| Plain text version | 6 KB |
| Inline signature image (linked via cid:) | 78 KB |
| Total .eml file | 141 KB |
Confirmed in live inbox testing on 15 May 2026.