Skip to content

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

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

fix(hubspot): simplify integration to only create contacts#7147
Holmus wants to merge 3 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)

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) <noreply@anthropic.com>
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 9, 2026 10:38am
flagsmith-frontend-preview Ignored Ignored Preview Apr 9, 2026 10:38am
flagsmith-frontend-staging Ignored Ignored Preview Apr 9, 2026 10:38am

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-frontend:pr-7147 Finished ✅ Results
ghcr.io/flagsmith/flagsmith-api-test:pr-7147 Finished ✅ Skipped
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.36%. Comparing base (c5af2d5) to head (60856fb).
⚠️ Report is 28 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #7147      +/-   ##
==========================================
+ Coverage   98.34%   98.36%   +0.02%     
==========================================
  Files        1336     1348      +12     
  Lines       50161    50570     +409     
==========================================
+ Hits        49331    49745     +414     
+ Misses        830      825       -5     

☔ 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)

@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).

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) <noreply@anthropic.com>
@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

contact_id=HUBSPOT_USER_ID,
company_id=HUBSPOT_COMPANY_ID,
)
mock_client_existing_contact.associate_contact_to_company.assert_not_called()
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.

This test name should reflect that associations are not created.

(Atm: test_create_lead__existing_hubspot_org__creates_contact_and_associates)

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.

Actually, associate_contact_to_company is only used in test now so we might want to clean it all up

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