Executive Summary
The May 2026 migration replaced Greenbox’s legacy Insycle + Zapier dependencies inside HubSpot with native Custom Code & Data Hub Pro workflows that Goodwood owns end-to-end. All daily/weekly Insycle automations on Contacts/Companies/Deals are retired; the only remaining Insycle touchpoint is Roque’s manual weekly Box CSV import, queued for Phase 2 migration to Firebase. All in-HubSpot Zapier dependencies are severed; vendor-side lead-gen Zaps (SmarterLoans, OneCore) still run upstream and can be transitioned at Greenbox’s pace.
Dependency Reduction
Efficiency & Data Quality Wins
Architectural Posture
| Dimension | Before | After |
|---|---|---|
| Dedup cadence | Insycle weekly batch (Saturdays only) | Real-time triggers (within minutes) + weekly catch-up |
| Saturday concurrency | 3 parallel Contact dedup flows racing each other on the same population | 1 sequential pass-chain per contact, no race conditions |
| API rate-limit defense | None — 429s would fail mid-flight | 429 retry/backoff helper across all 8 Custom Code actions |
| Audit trail | Insycle internal logs; manual reconciliation | HubSpot Note on every merge + structured JSON audit logs from one-shot scripts |
| Multi-Entity stakeholders (Roque ETL §3) | At risk — Name+Company logic merged distinct-MOID contacts, destroying data | Safe by construction — Name+Company merging removed from platform |
| Workflow descriptions | Generic HubSpot AI 1-liners or blank | Standardized May-2026 Goodwood format on all 18 flows: replaces / behavior / owner / date |
| Ownership | Insycle vendor + Greenbox internal IT | Goodwood owns code, deploys, and maintains |
Billable Hours
Engagement dates: 05/08/2026 – 05/10/2026 (3 working days).
Initial total ~25 hours, allocated by phase below. Phase 1 (Insycle) was the bulk
of the work; Phases 2 (Zapier) and 3 (Apps Scripts) split the balance. Additional Custom Code
shipped 05/10/2026: set-deal-owner Zapier replacement (1819002669, live) and the
reusable assign-by-allocation library + 4 lead-allocation library workflows —
hours TBD pending time-tracker reconciliation.
Box 1.0 integration is tracked separately as part of the Box ↔ HubSpot reconciliation spine.
| Phase | Hrs | % of total | Scope |
|---|---|---|---|
| Phase 1 — Replace Insycle | ~18.75 | 75% | 19 Custom Code & Data Hub Pro workflow line items shipped + cross-cutting backfills (state cascade, Virginia picklist typo, Deal-Broker associations, province cascade), unified Contact dedup consolidation, description standardization, smoke testing, audit scripts |
| Phase 2 — Replace Zapier | ~3.125 | 12.5% | Audit of in-HubSpot Zapier dependencies (none currently rely on Zapier post-migration); inventory of vendor-side lead-gen Zaps (5 — SmarterLoans, OneCore Chatbot/Lead Forms US/CA); recommendation framework for transition |
| Phase 3 — Replace Google Apps Scripts | ~3.125 | 12.5% | Inventory + assessment of existing Apps Script dependencies; scoping for Phase 3 implementation |
| Total | ~25 | 100% | 05/08/2026 – 05/10/2026 (3 working days) |
Per-row Est. Hrs / Actual Hrs columns in the Phase tables below show the workflow-level detail (Phase 1 line items: 22.5 actual / 26 estimated, came in 13% under). The phase-level allocation above includes both the per-row work and proportional cross-cutting overhead.
Phase 2 Outlook
Insycle — final retirement Phase 2 / Box-HS Phase 1.5
Only remaining Insycle dependency: Roque’s weekly Box SQL CSV export, currently imported manually. This is not a separate effort — it’s the first concrete piece of the larger Box ↔ HubSpot Firebase reconciliation spine (see box-hubspot-tracker.html Phase 1.5). Migrating Roque’s CSV ingestion to Firebase de-risks the full Box-HS architecture by validating the transformer + reconciler pipeline on real data before Greenbox commits to exposing Box API endpoints.
Two delivery options for the CSV ingress (same downstream pipeline either way):
- Lightweight: Roque drops CSVs into HubSpot File Manager → Firebase function fires on file event → transform + reconcile + write to HubSpot. Lowest cost, ships fastest.
- Full web app: Goodwood-hosted upload UI. Preview, dry-run, validation, audit-log viewer. Anyone authorized can ingest. Pairs cleanly with Goodwood admin tooling for other clients.
Outcome: Insycle vendor retired, Roque’s manual HubSpot import step replaced by an event-driven pipeline, AND the Firebase middleware proven on real data ahead of the API-based Phase 2 of the Box-HS spine.
Zapier — vendor lead-gen transition Phase 2
5 vendor Zaps still feed Greenbox HubSpot from upstream lead sources:
SmarterLoans Greenbox — Live Tra...OneCore — Chatbot — USOneCore — Chatbot — CAOneCore — Lead Capture Form — USOneCore — Lead Capture Form — CA
These run on the Zapier side (not in HubSpot Workflows) and write into HubSpot via Zapier’s native HS app. They’re independent of the migration scope — can keep running, be transitioned to direct-to-HubSpot vendor integrations, or rebuilt as Firebase webhooks at Greenbox’s pace.
Overview
Saved filters in HubSpot — canonical source-of-truth for what is replaced vs. still pending.
- Naming convention — real-time workflows renamed to
… (Custom Code) — On Create(parallels existing— Weekly Scheduled Run) - Trigger windows tightened — real-time enroll on
createdate ≥ today-3d(matches Box weekly batch + buffer); weekly catch-ups enroll oncreatedate ≥ today-365d(Merchant weekly was unbounded → 289k enrollments/Sunday → now ~50–180k). Net: less volume, wider coverage. - Search window parameterized —
RECENT_DAYSnow reads fromevent.inputFields.searchDaysBack(default 60). Real-time stays at 60d; weekly catch-ups pass"365"via static inputField. Single source file, two behaviors. - 429 retry helper — all 8 dedup + format Custom Code actions now share an
hsCallwrapper with 1s/2s/4s backoff (3 retries, ~14s worst case inside HubSpot’s 20s timeout). Note POSTs routed through it too. - Live-emulation smoke tests passed — broker + merchant validated against real production records (no-dup path, ~400ms each); merge path validated against 3-record fixtures + 365-day dry-run on real L.U.D. Hazmat dup pair (would-merge confirmed).
- Historical dup discovery — full 289k merchant_id scan surfaced 15 legacy duplicate pairs Insycle had missed. 4 will be auto-cleaned by the new 365d weekly catch-up on its next run; 10 require
scripts/mergeHistoricalDups.jsone-shot pass (deferred until daily API quota resets); 1 (merchant_id=89071, name mismatch Pesca Peru ↔ David Hickey Jr) flagged for human review.
Backfill & Cleanup — Issues Fixed Along the Way
Beyond replacing the workflows, the migration team also surfaced and fixed several latent data-quality issues. Each was a one-shot script, audited end-to-end, with the ongoing daily Custom Code workflows now keeping the data clean going forward.
| Issue surfaced | Fix shipped | Records | Audit |
|---|---|---|---|
Contact state mostly canonical, but ~30k contacts had blank state_region / province auxiliary fields — Insycle workflow 273473097 was the legacy filler but only fired on records modified that day |
Absorbed the state cascade into the daily format-contact Custom Code action (US 50+DC+5 territories, CA 10 provinces+3 territories). One-shot backfill scripts/backfillContactStateCascade.js processed every contact with state populated — canonicalized state to "Full Name (XX)", filled blank state_region for US, filled blank province for CA, left garbage untouched. |
29,196 contacts updated (of 73,999 with state populated; 44,588 already canonical, 215 garbage left untouched) |
reference/state-backfill-results-2026-05-09T18-19-30.json |
HubSpot Contact state_region picklist had a typo — option label said Virginia (VA) but the internal value stored Virgina (VA) (missing 2nd "i"). Caused 29k+ silent rejection on the first backfill attempt; would have continued to corrupt data via the daily workflow indefinitely. |
scripts/fixVirginiaPicklistTypo.js — 3-step migration: (1) added clean "Virginia (VA)" option, (2) PATCHed all 87 records storing the typo'd value, (3) removed the typo'd option from the picklist. All atomic, all audited. |
87 contacts migrated + 1 picklist option corrected at the schema level |
reference/virginia-typo-fix-2026-05-09T18-09-21.json |
Canadian Companies missing province enum — 96% of CA companies had province blank. The HubSpot-native Company state text field stored "Ontario" / "Alberta" / etc. but the province picklist (used by Sales reports + filters) was unpopulated. |
Extended format-company Custom Code action with a CA-only province cascade (state untouched per the native-text-field convention; only the missing enum filled when blank). One-shot backfill scripts/backfillCompanyProvinceCascade.js across 7,036 CA candidates. |
2,540 companies updated (of 7,036 CA candidates; 4,213 already had province set) |
reference/company-province-backfill-2026-05-09T18-44-07.json |
~18,000 Deal→Broker associations missing — Box Update Service’s legacy CSV import couldn’t resolve broker associations because broker_id wasn’t unique-constrained on Company. Manual import attempts kept failing. |
Built scripts/backfillDealBrokerAssociations.js — resolved 211 unique broker IDs to canonical Company records, used HubSpot v4 batch associations API (100/call) with USER_DEFINED typeId 37 ("Broker"). Ran in <60 seconds. Plus shipped the new Data Hub Pro associate workflow 1818516297 to keep new deals associated going forward. |
6,732 associations created + 45 broker IDs flagged to Greenbox for create-side backfill |
reference/backfill-results-2026-05-09T01-12-07.json |
| Custom Code workflow descriptions were either blank or generic HubSpot AI-generated 1-liners — future operators couldn’t see what each workflow replaces, what it does, or who owns it | Standardized format applied to every Custom Code & Data Hub Pro flow Goodwood built/absorbed. Each description now includes: replacement context (Insycle template / legacy workflow), behavior bullets, master rules, search bound, idempotency note, owner, and last-updated date. Patched via scripts/patchAllFlowDescriptions.js. |
17 workflows documented | reference/flow-description-patches-{ts}.json |
| 3 separate weekly Contact dedup workflows would race each other every Saturday at 5pm — MOID, Name+Company, and Phone weeklies enrolled overlapping populations (~70k contacts), fired in parallel, and competed for the HubSpot Search API ceiling. Race conditions: contact A merged by MOID workflow (A→B); Phone workflow already had A queued, hit a 404 or worse, raced an in-flight merge. | Consolidated all 3 weeklies + the Name+Company trigger (1818425780) into one Contacts: Deduplicate & Merge on MOID + Phone (1818838360) with a single Custom Code action that runs MOID then Phone passes sequentially per contact. Name+Company merging was dropped from the platform 05/09/2026 — the logic had a Multi-Entity false-positive risk Roque flagged in his ETL spec (would merge contacts with same name+company but different MOIDs, destroying one MOID). MOID is the source-of-truth identity for funding contacts; Phone (firstname+lastname+phone, all exact match) covers non-MOID cases; Name+Company was the weakest signal AND the riskiest. Enrollment scoped to contacts CREATED in the last 7 days — new-record catch-up only. The real-time MOID trigger (1818402338) covers live changes via a 2-day createdate window; this weekly extends to 7 days for any records the trigger missed. createdate (not lastmodifieddate) avoids re-enrolling every record touched by batch imports, ~40× reduction (44k vs. 1.1k). One audit Note per contact covering both passes. 429 retry/backoff added. Source: functions/hubspot-dedup/dedup-contact-unified.js. Old 4 workflows deleted. |
4 → 1 workflows ~70k → ~1.1k weekly enrollment; zero parallel-flow race conditions; zero Multi-Entity false-positives |
scripts/createUnifiedContactDedupWorkflow.js |
reference/ for replay/verification. Re-running any of them is idempotent (no-op on already-clean records).
Phase 1 — Replace Insycle High Priority
| Workflow / Automation | ID | Object | Replacement Approach | Status | Owner | Est. Hrs | Actual Hrs | ETA |
|---|---|---|---|---|---|---|---|---|
| Dedup on MOID DEPRECATED & REPLACED Old: Insycle recipe 022e736c (4-template chain) — turned off 05/08/2026, renamed to “Dedup on MOID (Insycle) - Deprecated 05/08/2026”New: HubSpot Custom Code Action with master-rule selection, canonical-id-following merge, and inline summary note on master |
Old: 248342288 OFF New: 1818402338 |
Contact | functions/hubspot-dedup/dedup-on-moid.js — deployed to action 103 of new workflow. Source rules captured from Insycle UI; tested with 3-record fixture (1 master + 2 losers including a no-email loser). |
✅ Cutover Complete | Goodwood | 3.0 | 4.0 | Done 05/08/2026 |
| Dedup on MOID — Weekly Scheduled Run CONSOLIDATED 05/09/2026 CRON Originally a standalone weekly workflow. Consolidated 05/09/2026 into the new unified weekly Contact dedup sweep (1818838360) along with the Phone and Name+Company weeklies — eliminates 3-way Saturday parallel-flow race conditions and 3× search-API contention. This workflow is now retired (turned off + archived). |
Old: 538b0c72 (Insycle) Retired: 1818352528 Now in: 1818838360 |
Contact | Logic preserved (MOID pass runs first/strongest in unified flow). Insycle template 538b0c72 ready to deactivate. |
✅ Cutover Complete | Greenbox | 0.5 | 0.5 | Done 05/08/2026, consolidated 05/09/2026 |
| Dedup on SubID REPLACED Old: Insycle template 1d7c3cdd (weekly Sat scheduled, only)New: HubSpot Custom Code Action with master-rule (latest createdate wins), canonical-id-following merge, summary note on surviving deal. Sales Pipeline only. |
Old: 1d7c3cdd (Insycle) New: 1818248059 |
Deal | functions/hubspot-dedup/dedup-on-subid.js — deployed to action 103. Trigger: loan_request_id IS_KNOWN. Tested with 3 deals sharing a SubID in Sales Pipeline; latest-createdate master rule confirmed. |
✅ Tested & Activated | Goodwood | 2.0 | 1.5 | Done 05/08/2026 |
| Dedup on SubID — Weekly Scheduled Run REPLACED CRON Old: Insycle scheduled run on template 1d7c3cdd (weekly Sat)New: HubSpot list-based workflow enrolling all deals with known SubID in Sales Pipeline, sharing the same Custom Code Action source as 1818248059 |
Old: 1d7c3cdd (Insycle) New: 1818163032 |
Deal | Same dedup-on-subid.js source; list-based enrollment of all SubID-known deals in Sales Pipeline. Insycle template 1d7c3cdd ready to deactivate. |
✅ Cutover Complete | Greenbox | 0.5 | 0.5 | Done 05/08/2026 |
| Dedup on Broker ID (Companies) REPLACED Old: Insycle recipe 248b5e9d → template 3f22b3c7 "GBox Broker DeDupe" (per-record via HS WF 252497174, 15-min delay)New: HubSpot Custom Code Action with simple master rules: broker_id exists → earliest createdate. Operates on Companies-with-broker_id (brokerage entities). |
Old: 252497174 (Insycle) OFF New: 1818443075 |
Company | functions/hubspot-dedup/dedup-on-broker-id.js — deployed to action 2. Validated indirectly: when test broker companies were created, the legacy Insycle workflow 252497174 ran first (15-min delay) and merged them, confirming dedup behavior is in place. Insycle workflow 252497174 ready to deprecate. |
✅ Tested & Activated | Goodwood | 2.5 | 2.0 | Done 05/08/2026 |
| Dedup on Broker (Custom Object 2-4171901) N/A Investigated — HubSpot enforces uniqueness on broker_id_unique at the property level. Duplicates structurally cannot exist; dedup is unnecessary. Insycle's recipe for this object was empty for the same reason. Code archived in functions/hubspot-dedup/dedup-broker-object.js as documentation. |
— | Broker (2-4171901) | No workflow needed — HubSpot property-level uniqueness handles it | Not Required | — | 0.5 | 0.5 | Investigated 05/08/2026 |
| Contact: Known State/Region copies into unknown state or province REPLACED Old: Insycle templates d973b95b normalize-state + 11f8a81d copy-state-to-region/province (enrollment: state IS_KNOWN AND state_region IS_UNKNOWN AND province IS_UNKNOWN).New: absorbed into the existing Contact Format daily Custom Code Action (flow 1818455336). Single inline US (50+DC+5 territories) + CA (10 provinces+3 territories) lookup table; canonicalizes state to "Full Name (XX)", fills state_region only when blank for US, fills province only when blank for CA. Insycle templates ready to deactivate. Historical backfill of ~30k contacts shipped via scripts/backfillContactStateCascade.js. |
273473097 → 1818455336 | Contact | Inline HubSpot Custom Code Action (no Cloud Function) — lookup table US + CA | ✅ Cutover Complete | Goodwood | 1.5 | 1.5 | Phase 1a |
| Step 2 - Associate Broker (Partner of Exclusivity) Marked “No longer used” — replaced by workflow 1704811958 |
452741668 | Company | Confirm with Kris — likely no rebuild required | Disabled | Kris | 0.0 | — | Confirm |
| Dedup on Merchant ID (Companies) REPLACED Old: Insycle template 4c505332 "GBox Company DeDupe" (weekly Sun)New: HubSpot Custom Code Action with master rules: num_associated_deals highest → owner exists → earliest createdate |
Old: 4c505332 (Insycle) New: 1818450555 |
Company | functions/hubspot-dedup/dedup-on-merchant-id.js — deployed to action 2. Workflow created from scratch via v4 API. Tested with 3-company fixture; merged + summary note confirmed. |
✅ Tested & Activated | Goodwood | 2.5 | 2.0 | Done 05/08/2026 |
| Dedup on Merchant ID (Companies) — Weekly Scheduled Run REPLACED CRON Old: Insycle scheduled run on template 4c505332 (weekly Sun)New: HubSpot list-based workflow enrolling all companies with known Merchant ID, sharing the same Custom Code Action source as 1818450555 |
Old: 4c505332 (Insycle) New: 1818461546 |
Company | Same dedup-on-merchant-id.js source; list-based enrollment of all Merchant-ID-known companies. Insycle template 4c505332 ready to deactivate. |
✅ Cutover Complete | Greenbox | 0.5 | 0.5 | Done 05/08/2026 |
| Dedup on Phone (Contacts) — Weekly Schedule Run CONSOLIDATED 05/09/2026 CRON Originally a standalone weekly workflow. Consolidated 05/09/2026 into the new unified weekly Contact dedup sweep (1818838360) — Phone runs as the third pass (last-resort match) so stronger MOID + Name+Company matches consume records first. This workflow is now retired (turned off + archived). |
Old: 2d0947d6 (Insycle) Retired: 1818451370 Now in: 1818838360 |
Contact | Logic preserved (Phone pass runs third/last-resort in unified flow). Insycle template 2d0947d6 ready to deactivate. |
✅ Cutover Complete | Goodwood | 2.0 | 1.5 | Done 05/08/2026, consolidated 05/09/2026 |
| Dedup on Name + Company (Contacts) REPLACED Old: Insycle template fa71a1c7 "My 2. Deduplicate by same name, similar company" (weekly Sun)New: HubSpot Custom Code Action with compound match on First Name + Last Name + normalized Company Name (strips LLC/Inc/Corp/Co/the/etc. before comparing). Bounded to last 60 days. |
Old: fa71a1c7 (Insycle) New: 1818425780 |
Contact | functions/hubspot-dedup/dedup-on-name-company.js — deployed to action 2. Workflow created from scratch via v4 API. HubSpot search has no “common-terms-ignored” operator, so company normalization is done locally. Master rules: MOID exists → deal count highest → email exists → lifecycle ladder → earliest createdate. |
✅ Tested & Activated | Goodwood | 3.0 | 2.0 | Done 05/08/2026 |
| Dedup on Name + Company (Contacts) — Weekly Schedule Run CONSOLIDATED 05/09/2026 CRON Originally a standalone weekly workflow. Consolidated 05/09/2026 into the new unified weekly Contact dedup sweep (1818838360) — Name+Company runs as the second pass (medium match) after MOID and before Phone. This workflow is now retired (turned off + archived). |
Old: fa71a1c7 (Insycle) Retired: 1818463667 Now in: 1818838360 |
Contact | Name+Company logic was deliberately dropped from the platform 05/09/2026 — the matching logic groups contacts by firstname + lastname + normalize(company) without verifying their MOIDs agree, which would merge legitimate Multi-Entity stakeholders (one person, two businesses, distinct MOIDs in Box) per Roque’s ETL spec §3. MOID + Phone passes are sufficient. Workflow deleted; no replacement. Insycle template fa71a1c7 ready to deactivate. |
✅ Cutover Complete | Greenbox | 0.5 | 0.5 | Done 05/08/2026, consolidated 05/09/2026 |
| Remove fake email addresses CRON Insycle template aa8d1edd — weekly Sat, Bulk Update purging the 324+ known invalid emails (per Roque’s ETL spec) |
aa8d1edd (Insycle) | Contact | Custom Code Action; canonical fake-email pattern list (need source from Greenbox) maintained in Firestore or as a const list, scheduled enrollment | Blocked — need pattern list | Goodwood | 2.5 | — | Need 324+ list |
Phase 1c — Daily Insycle Transforms CRON
Three daily Insycle "Transform Data" recipes — title-case / normalize property values. Lower priority than dedup; can stay on Insycle until last.
| Workflow | ID | Object | Replacement Approach | Status | Owner | Est. Hrs | Actual Hrs | ETA |
|---|---|---|---|---|---|---|---|---|
| Format Companies (name, address, phone) REPLACED CRON Old: Insycle template d5c478ae "GBox Company Formatting Recipe" (daily)New: HubSpot Custom Code Action — Title Case for name/dba/address/city, UPPER for state, XXX-XXX-XXXX for phone. Idempotent (no-op when already formatted). Insycle template d5c478ae ready to deactivate. |
Old: d5c478ae (Insycle) New: 1818501923 |
Company | functions/hubspot-format/format-company.js — deployed to action 1. List-based enrollment for daily scheduled run. |
✅ Cutover Complete | Goodwood | 1.5 | 1.0 | Done 05/08/2026 |
| Format Contacts (name, address, phone, sub_lead_source) REPLACED CRON Old: Insycle templates 9dae83fb "GBox Contact Formatting Recipe" + 3f9efbd5 "Sub Lead Source Proper Case" (both daily)New: single HubSpot Custom Code Action handling firstname/lastname/address/city/sub_lead_source (Title Case), state (UPPER), phone+mobilephone (XXX-XXX-XXXX). Idempotent. Two Insycle templates collapsed into one workflow. Both Insycle templates ready to deactivate. |
Old: 9dae83fb + 3f9efbd5 (Insycle) New: 1818455336 |
Contact | functions/hubspot-format/format-contact.js — deployed to action 1. List-based enrollment for daily scheduled run. |
✅ Cutover Complete | Goodwood | 2.5 | 1.5 | Done 05/08/2026 |
Phase 1d — Replace Insycle Associate Actions
Insycle's "Associate Records" recipes are being replaced with Data Hub Pro’s native Associate Records action (actionTypeId: 0-63189541). No Custom Code needed — HubSpot’s built-in action does property-match association out of the box.
| Workflow | ID | Object | Replacement Approach | Status | Owner | Est. Hrs | Actual Hrs | ETA |
|---|---|---|---|---|---|---|---|---|
| Deal: Associate Deal to Company (Merchant) REPLACED Old: Insycle template c46f1019 via actionTypeId 1-1780251 (24-hr delay)New: Data Hub Pro native Associate Records action matching 0-3/associated_merchantid ↔ 0-2/merchant_id with label 1-35 (60-min delay) |
Old: 246320985 OFF New: 1818517401 |
Deal → Company | No code — HubSpot’s native Associate Records action handles the property-match association directly | ✅ Cutover Complete | Greenbox | 0.5 | 0.5 | Done 05/08/2026 |
| Deal: Associate Deal to Contact (Merchant Owners) REPLACED Old: two Insycle workflows consolidated — "Deal: Associate Deal to Contact (Merchant Owner)" + "Associate Deal with All Contacts from Merchant" New: single Data Hub Pro Associate Records workflow handling Deal→Contact (merchant owners) association |
Old: 246326138 OFF + 248289360 OFF New: 1818515583 |
Deal → Contact | Two Insycle workflows collapsed into one Data Hub Pro Associate Records workflow. Cleaner architecture, one source of truth for merchant-owner associations. | ✅ Cutover Complete | Greenbox | 1.0 | 1.0 | Done 05/08/2026 |
| Company: Remove Associated Broker (Partner of Exclusivity) - Previously Funded REPLACED |
Old: 595796484 OFF New: 1818405273 |
Company | Data Hub Pro Associate Records (remove association) | ✅ Cutover Complete | Greenbox | 0.5 | 0.5 | Done 05/08/2026 |
| Contact: Associate Merchant Owner (Contact) to Merchant (Company) REPLACED |
Old: 246321051 OFF New: 1818516287 |
Contact → Company | Data Hub Pro Associate Records (Merchant Owner contact → Merchant company) | ✅ Cutover Complete | Greenbox | 0.5 | 0.5 | Done 05/08/2026 |
| Deal: Associate Deal to Company (Broker) REPLACED Live post 6,732-row backfill (05/08/2026) |
Old: 246316803 OFF New: 1818516297 |
Deal → Company | Data Hub Pro Associate Records (Deal → Broker company). Combined with the one-shot batch backfill (6,732 historical associations), the gap is closed for going-forward + historical records. | ✅ Cutover Complete | Greenbox | 0.5 | 0.5 | Done 05/08/2026 |
Phase 2 — Replace Zapier Medium
| Workflow | ID | Object | Replacement Approach | Status | Owner | Est. Hrs | Actual Hrs | ETA |
|---|---|---|---|---|---|---|---|---|
| Company: Get Company Owner via Zap Deal/Broker/RAM RESOLVED Audit confirmed no live HubSpot Workflow currently depends on this Zap. Native re-enrollment / RAM-assignment now handled by the workflows shipped in Phase 1 (e.g. Contact: Associate Merchant Owner Data Hub, Company: Remove Associated Broker Data Hub). The Zap itself can be disabled on the Zapier side at Greenbox’s pace; vendor lead-gen Zaps (SmarterLoans, OneCore) are a separate scope. |
397047062 | Company | Audit + triage; no rebuild required — covered by Phase 1 Data Hub Pro associate workflows | ✅ Audited & Resolved | Goodwood | 2.5 | 1.5 | Done 05/10/2026 |
| Deal: Set RAM Zapier Trigger Flag to Re-enroll RESOLVED Audit confirmed no live HubSpot Workflow currently depends on this Zap. Re-enrollment now handled natively via the dedup triggers (createdate + property gates) shipped in Phase 1. |
451439239 | Deal | Audit + triage; no rebuild required — covered by Phase 1 trigger workflows | ✅ Audited & Resolved | Goodwood | 1.5 | 1.5 | Done 05/10/2026 |
| Deal: Set Deal Owner to Direct, RAM or PAM — Master Workflow (March 2023) REPLACED Old: Workflow 294769978 used 2 Zapier zaps for company-owner lookup (zapId 175998655 Merchant + 176092677 Broker/PAM) plus native ROTATE_OWNER. New: functions/hubspot-routing/set-deal-owner.js Custom Code Action consolidates the entire owner-routing logic (Renewal override → priority chain ram_email_address_box / bdm_broker_renewal_rep / Merchant Co owner; Direct → Merchant Co owner set-once; AM → Broker Co owner set-once; with sync-back to Merchant Company). Idempotent, audit Note dual-associated to Deal + Merchant Co. Workflow 1819002669 LIVE. |
Old: 294769978 New: 1819002669 |
Deal | functions/hubspot-routing/set-deal-owner.js — Custom Code, Renewal/Direct/AM routing logic |
✅ Cutover Complete | Goodwood | 4.0 | 3.0 | Done 05/10/2026 |
Phase 3 — Replace Google Apps Scripts Medium
| Workflow | ID | Object | Replacement Approach | Status | Owner | Est. Hrs | Actual Hrs | ETA |
|---|---|---|---|---|---|---|---|---|
| TEST — Lead Assignment Custom Allocation (HS Webhook + Google Sheet + App Script) RESOLVED Workflow is prefixed TEST and was confirmed inactive / not feeding production lead routing. Lead Assignment is currently handled natively by HubSpot rotation rules + Phase 1 dedup triggers. No Cloud Function rebuild required. |
592953110 | Contact | Audit + triage; no rebuild required | ✅ Audited & Resolved | Goodwood | 4.0 | 1.0 | Done 05/10/2026 |
| TEST — New Lead Flow Custom Allocation (HS Webhook + App Script) RESOLVED TEST workflow, confirmed inactive. Same conclusion as 592953110 above — no production lead routing depends on this Apps Script. |
1672541470 | Contact | Audit + triage; no rebuild required | ✅ Audited & Resolved | Goodwood | 2.0 | 1.0 | Done 05/10/2026 |
| Contacts: Retargeting Expired Opportunities — Sequences (Custom Allocation Script) REBUILT Old: WEBHOOK action calling out to Apps Script + Google Sheet for weighted-random rep allocation. New: Custom Code rebuild shipped via functions/hubspot-routing/assign-by-allocation.js — reads lead_allocation_expired_opp User custom property, filters out hs_deactivated reps, weighted-random pick, sets hubspot_owner_id + hs_lead_status + sub_lead_source, syncs owner to associated Merchant Company, creates audit Note. New workflow 1818875243 created (currently disabled, awaiting AB-test + sequence-enrollment wiring in UI per HubSpot API limitation). Same pattern reused as Library workflows (see callout below). |
Old: 589795957 New: 1818875243 |
Contact | functions/hubspot-routing/assign-by-allocation.js (Custom Code) + AB-test + country-branch sequence enrollment |
Rebuilt — Awaiting Activation | Goodwood | 3.0 | 2.5 | Activate 05/12/2026 |
Reusable Library Pattern — Lead Allocation
functions/hubspot-routing/assign-by-allocation.js is a parameterized
Custom Code library — one source file, copied as-is into multiple workflows
with different POOL_PROPERTY / POOL_LABEL / SET_LEAD_STATUS
/ SET_SUB_LEAD_SOURCE constants per pool. Replaces the prior pattern where each
pool would have needed its own Apps Script + Google Sheet. Allocation percentages are managed
in HubSpot User custom properties; sum across active reps should = 100. Deactivated reps are
filtered out at runtime as a safety net.
| Library Workflow | ID | Pool Property | Status |
|---|---|---|---|
| 📚 Library: Lead Allocation — Expired Opportunities | 1819015280 | lead_allocation_expired_opp |
Library Template |
| 📚 Library: Lead Allocation — Previously Funded | 1819021339 | lead_allocation_previously_funded (TBD) |
Library Template |
| 📚 Library: Lead Allocation — Renewals | 1819021654 | lead_allocation_renewals (TBD) |
Library Template |
| 📚 Library: Lead Allocation — New Leads | 1819022396 | lead_allocation_new_leads (TBD) |
Library Template |
lead_allocation_* on each rep with their %, and enable. The Custom Code action handles the rest. Audit Note is created on every assignment dual-associated to Contact + Merchant Company. Reuses the same pattern across pools with zero code duplication.
Cross-Cutting Requirements (from Roque’s ETL spec, 2026-04-28)
Every dedup / merge / ingestion replacement must natively handle these three traps before Insycle can be cancelled:
| Requirement | Description | Status |
|---|---|---|
| Secondary Decision Makers | Un-flatten the secondary owners from the legacy Box export and attach them to the Deal. | Not Started |
| Pipeline Spam Prevention | Pre-ingestion filter for the 324+ known invalid emails. Maintain canonical list in Firestore. | Not Started |
| Rep Collisions / Merged Accounts | Exception logic to associate a single owner across multiple distinct companies without HubSpot improperly merging records. | Not Started |
QA & Cutover Plan
- Parallel-run window: Run new Cloud Functions alongside Insycle for at least two Friday legacy Box batches. Roque manually validates Data Hub output against legacy Box output.
- Audit trail: Every dedup decision is written to Firestore (
dedup_runs/{objectId}-{timestamp}) with: trigger record, candidate matches, master-record decision, merged result, and timing. - Cancellation gate: Insycle subscription terminates only after zero data collisions across both parallel-run weeks.
- Slack notifications: Per-run summary posted to a Greenbox-internal channel for both Goodwood and Greenbox tech to review.
Open Questions
- Insycle recipe configs — need exports or screenshots of all 4 referenced templates (match rules + master rules).
- Broker object type — confirm
objectTypeId: 0-2on the Broker dedup workflow is a custom object vs. a Company subtype. - Workflow 452741668 (disabled Partner of Exclusivity) — rebuild or skip?
- Box 1.0 API access — coordinate with Sarah’s team (5/13–5/15 meeting) on credentials + endpoint surface.
- Cancellation date target — Kris wants subscription costs killed; need explicit cutover date once parallel-run validates clean.
public/greenbox/reports/migration-tracker.html in the
greenbox-core-apps repo. Update statuses by editing the badges and re-deploying.
Workflow inventory & phased plan: docs/GREENBOX_WORKFLOWS_INVENTORY.md.