Skip to content

fix(hubspot): simplify integration to only create contacts#7147

Open
Holmus wants to merge 4 commits intomainfrom
fix/hubspot-let-hubspot-handle-companies
Open

fix(hubspot): simplify integration to only create contacts#7147
Holmus wants to merge 4 commits intomainfrom
fix/hubspot-let-hubspot-handle-companies

Conversation

@Holmus
Copy link
Copy Markdown
Contributor

@Holmus Holmus commented Apr 7, 2026

The HubSpot lead tracking integration was doing three things:

  1. Creating contacts (via form submission)
  2. Creating/updating companies with Flagsmith org names - overwriting HubSpot-enriched data
  3. Syncing subscription/plan changes to HubSpot companies

Problems with (2): Flagsmith org names like "ew", "Test", "Manejo-Org" overwrote enriched company names in HubSpot.

Problems with (3): This was redundant with our ChargeBee -> HubSpot sync (which runs daily and is the billing source of truth). Worse, it caused data confusion - trial subscriptions written by the integration were treated as paid accounts, triggering workflows that incorrectly set company type to Customer.

Changes

  • Simplify create_lead to only create the contact - HubSpot handles company creation and association from email domains
  • Simplify should_track to just check if the feature is enabled
  • Remove update_company_active_subscription and its AFTER_SAVE hook - ChargeBee sync is the source of truth for subscription data
  • Remove _get_organisation_hubspot_id and _get_hubspot_company_by_domain (dead code after above)
  • Remove associated tests

What still works

  • Contact creation via form submission
  • HubSpot auto-creates and associates companies from contact email domains
  • ChargeBee sync writes subscription, MRR, billing status, plan data daily
  • HubspotOrganisation model is unchanged (existing records preserved)

Review effort: 1/5 (almost entirely deletions)

Copy link
Copy Markdown

@claude claude Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Code review skipped — your organization's overage spend limit has been reached.

Code review is billed via overage credits. To resume reviews, an organization admin can raise the monthly limit at claude.ai/admin-settings/claude-code.

Once credits are available, reopen this pull request to trigger a review.

@Holmus Holmus requested a review from a team as a code owner April 7, 2026 07:59
@Holmus Holmus requested review from khvn26 and removed request for a team April 7, 2026 07:59
@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 7, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

3 Skipped Deployments
Project Deployment Actions Updated (UTC)
docs Ignored Ignored Preview Apr 21, 2026 1:36pm
flagsmith-frontend-preview Ignored Ignored Preview Apr 21, 2026 1:36pm
flagsmith-frontend-staging Ignored Ignored Preview Apr 21, 2026 1:36pm

Request Review

@github-actions github-actions Bot added api Issue related to the REST API fix labels Apr 7, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 7, 2026

Docker builds report

Image Build Status Security report
ghcr.io/flagsmith/flagsmith-e2e:pr-7147 Finished ✅ Skipped
ghcr.io/flagsmith/flagsmith-api-test:pr-7147 Finished ✅ Skipped
ghcr.io/flagsmith/flagsmith-frontend:pr-7147 Finished ✅ Results
ghcr.io/flagsmith/flagsmith-api:pr-7147 Finished ✅ Results
ghcr.io/flagsmith/flagsmith:pr-7147 Finished ✅ Results
ghcr.io/flagsmith/flagsmith-private-cloud:pr-7147 Finished ✅ Results

@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 7, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.38%. Comparing base (0c96217) to head (d61fa0d).
⚠️ Report is 2 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff            @@
##             main    #7147    +/-   ##
========================================
  Coverage   98.37%   98.38%            
========================================
  Files        1366     1366            
  Lines       51215    51081   -134     
========================================
- Hits        50384    50257   -127     
+ Misses        831      824     -7     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 7, 2026

Playwright Test Results (oss - depot-ubuntu-latest-16)

passed  10 passed

Details

stats  10 tests across 7 suites
duration  37.6 seconds
commit  ba4aa50
info  🔄 Run: #15815 (attempt 1)

Playwright Test Results (oss - depot-ubuntu-latest-arm-16)

passed  10 passed

Details

stats  10 tests across 7 suites
duration  28.6 seconds
commit  ba4aa50
info  🔄 Run: #15815 (attempt 1)

Playwright Test Results (private-cloud - depot-ubuntu-latest-arm-16)

passed  16 passed

Details

stats  16 tests across 13 suites
duration  1 minute, 3 seconds
commit  ba4aa50
info  🔄 Run: #15815 (attempt 1)

Playwright Test Results (private-cloud - depot-ubuntu-latest-16)

passed  2 passed

Details

stats  2 tests across 2 suites
duration  56.2 seconds
commit  ba4aa50
info  🔄 Run: #15815 (attempt 1)

Playwright Test Results (oss - depot-ubuntu-latest-16)

passed  11 passed

Details

stats  11 tests across 8 suites
duration  44 seconds
commit  d4d1f88
info  🔄 Run: #15923 (attempt 1)

Playwright Test Results (oss - depot-ubuntu-latest-arm-16)

passed  11 passed

Details

stats  11 tests across 8 suites
duration  11.9 seconds
commit  d4d1f88
info  🔄 Run: #15923 (attempt 1)

Playwright Test Results (oss - depot-ubuntu-latest-16)

passed  11 passed

Details

stats  11 tests across 8 suites
duration  9.4 seconds
commit  60856fb
info  🔄 Run: #15924 (attempt 1)

Playwright Test Results (oss - depot-ubuntu-latest-arm-16)

passed  11 passed

Details

stats  11 tests across 8 suites
duration  54.1 seconds
commit  60856fb
info  🔄 Run: #15924 (attempt 1)

Playwright Test Results (private-cloud - depot-ubuntu-latest-16)

passed  1 passed

Details

stats  1 test across 1 suite
duration  58.2 seconds
commit  d4d1f88
info  🔄 Run: #15923 (attempt 1)

Playwright Test Results (private-cloud - depot-ubuntu-latest-arm-16)

passed  17 passed

Details

stats  17 tests across 14 suites
duration  1 minute, 3 seconds
commit  d4d1f88
info  🔄 Run: #15923 (attempt 1)

Playwright Test Results (oss - depot-ubuntu-latest-16)

passed  11 passed

Details

stats  11 tests across 8 suites
duration  24.3 seconds
commit  d61fa0d
info  🔄 Run: #16215 (attempt 1)

Playwright Test Results (oss - depot-ubuntu-latest-arm-16)

passed  11 passed

Details

stats  11 tests across 8 suites
duration  47.9 seconds
commit  d61fa0d
info  🔄 Run: #16215 (attempt 1)

Playwright Test Results (private-cloud - depot-ubuntu-latest-16)

passed  2 passed

Details

stats  2 tests across 2 suites
duration  46.4 seconds
commit  d61fa0d
info  🔄 Run: #16215 (attempt 1)

Playwright Test Results (private-cloud - depot-ubuntu-latest-arm-16)

passed  2 passed

Details

stats  2 tests across 2 suites
duration  1 minute, 12 seconds
commit  d61fa0d
info  🔄 Run: #16215 (attempt 1)

@matthewelwell matthewelwell requested a review from Zaimwa9 April 7, 2026 10:41
Copy link
Copy Markdown
Contributor

@Zaimwa9 Zaimwa9 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I get the overall intent of this PR. Although there is a side-effect that feels critical to me -> We are breaking the synchronization between flagsmith and hubspot (even in read-only) and we might be unable to update the subscription to Hubspot.

My understanding with this code is that hubspot will be completely in control of creating the organisation AND the association of the contacts. That makes sense.

Right now, _get_organisation_hubspot_id is in charge of finding the organisation and creating the HubspotOrganisation record. It became dead code and we are never storing the information on our side.
It becomes a problem in update_company_active_subscription that is now a no-op (we don't have hubspot_id) and I feel using the domain or the name is too fragile.

My proposal
The fix should keep _get_organisation_hubspot_id in create_lead and drop the name= overwrite and keep writing flagsmith_organisation_id to HubSpot.
Optionally we can remove associate_contact_to_company to make our intent 100% clear and remove the associated tests (that just confirms it's never called right?).

Let me know what you think and i'll re-review with your thinking in mind.


If aligned, here is a final assist 😄

For Claude

  1. In _get_organisation_hubspot_id, remove the name=organisation.name parameter from the self.client.update_company(...) call but keep hubspot_company_id and flagsmith_organisation_id.
  2. In create_lead, keep the call to _get_organisation_hubspot_id but remove  associate_contact_to_company and the early returns tied to it.
  3. Update/remove tests that assert associate_contact_to_company behaviour.
  4. Remove any now-unused imports (e.g. re2/re if domain filtering stays removed).

@Holmus Holmus changed the title fix(Integrations): Let HubSpot handle company creation and association fix(hubspot): simplify integration to only create contacts Apr 9, 2026
@github-actions github-actions Bot added fix and removed fix labels Apr 9, 2026
@Holmus
Copy link
Copy Markdown
Contributor Author

Holmus commented Apr 9, 2026

Thanks for the review @Zaimwa9 - good catch on update_company_active_subscription becoming a no-op.

After thinking through it more, I went further than your proposal: I removed update_company_active_subscription entirely rather than fixing it.

Why: We have a ChargeBee -> HubSpot sync that runs daily and writes subscription data (plan, MRR, billing status, contract dates) to HubSpot companies. It's the billing source of truth. Having the Flagsmith integration also write subscription data was:

Redundant - ChargeBee sync already handles this
Harmful - the integration can't distinguish trial vs paid. We found cases where trial subscription data triggered workflows to incorrectly set companies as paying customers
So the integration now only does one thing: create the contact. HubSpot handles company creation from email domains, and ChargeBee sync handles all subscription/billing data.

The new commit removes update_company_active_subscription, its task, the AFTER_SAVE hook, and associated dead code (_get_organisation_hubspot_id, _get_hubspot_company_by_domain).

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 9, 2026

Visual Regression

16 screenshots compared. See report for details.
View full report

Copy link
Copy Markdown
Contributor

@Zaimwa9 Zaimwa9 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry to be annoying. Couple of NITs that we should take care of now:

  • Code removal
  • Unused variables

Then i'll be happy to approve assuming all ✅ on the functionality


domain = user.email_domain

if settings.HUBSPOT_IGNORE_DOMAINS_REGEX and re.match(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's clean those HUBSPOT_XXX from the settings please

@Zaimwa9
Copy link
Copy Markdown
Contributor

Zaimwa9 commented Apr 21, 2026

@Holmus do you want me to take over this one ?

Holmus and others added 4 commits April 21, 2026 15:33
The HubSpot lead tracking integration was creating and updating
companies from Flagsmith org data, overwriting enriched company
names with user-entered org names. HubSpot already handles company
creation and contact association automatically from email domains.

Simplify create_lead to only create the contact. Remove domain
filtering from should_track since HubSpot handles that natively.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
The Flagsmith integration writing subscription/plan data to HubSpot was
redundant (ChargeBee sync handles this daily) and caused confusion - trial
subscriptions were being treated as paid accounts, overwriting correct data.

- Remove update_company_active_subscription method and task
- Remove AFTER_SAVE hook on Subscription.plan
- Remove _get_organisation_hubspot_id (wrote org name + plan to HubSpot)
- Remove _get_hubspot_company_by_domain (only used by above)
- Remove associated tests

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Clean up unused HUBSPOT_IGNORE_* settings, remove the dead
associate_contact_to_company client method and its test, and rename
the existing-org test to reflect that associations are no longer created.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
@Holmus Holmus force-pushed the fix/hubspot-let-hubspot-handle-companies branch from 60856fb to d61fa0d Compare April 21, 2026 13:36
@Holmus Holmus requested a review from a team as a code owner April 21, 2026 13:36
Copy link
Copy Markdown
Contributor

@Zaimwa9 Zaimwa9 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! 🥇

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

api Issue related to the REST API fix

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants