hotchand / module-hubspot-sync
Magento 2 extension to seamlessly synchronize customers and orders to HubSpot CRM.
Package info
github.com/Hotchand/Magento2---sync-orders-and-customers-to-Hubspot-CRM
Type:magento2-module
pkg:composer/hotchand/module-hubspot-sync
Requires
- php: ^8.1 || ^8.2 || ^8.3
- hubspot/api-client: ^9.0 || ^10.0
- magento/framework: ^103.0
- magento/module-customer: *
- magento/module-sales: *
This package is auto-updated.
Last update: 2026-08-05 21:46:02 UTC
README
Syncs Magento 2 customers → HubSpot contacts and orders → HubSpot deals (associated to the matching contact by email).
Why a queue instead of calling the API on save?
Calling out to HubSpot synchronously from customer_save_after /
sales_order_save_after would add API latency to checkout and admin saves,
and a HubSpot outage or rate limit would start throwing errors at your
customers. Instead:
- Observers just write a row to
hotchand_hubspot_sync_queue(fast, local, no network call). - A cron job (
*/5 * * * *by default) picks up pending rows in batches and calls the HubSpot CRM v3 API, using the batch upsert endpoint for contacts (up to 100 per request) to stay well inside rate limits. - Failures are retried up to
max_attemptstimes, then markedfailedand visible in the admin grid under Sales → HubSpot Sync Queue.
Installation
# if pulling from a private repo / packagist composer require hotchand/module-hubspot-sync # or copy the app/code/Hotchand/HubspotSync directory directly, then: bin/magento module:enable Hotchand_HubspotSync bin/magento setup:upgrade bin/magento setup:di:compile bin/magento cache:flush
If installing via composer require, place these files under
app/code/Hotchand/HubspotSync for a straight code-drop, or set up a private
Packagist/Satis repo pointing at this package for a proper Composer install.
Configuration
Stores → Configuration → Hotchand → HubSpot Sync
- In HubSpot, create a Private App (Settings → Integrations → Private
Apps) with these scopes:
crm.objects.contacts.writecrm.objects.contacts.readcrm.objects.deals.writecrm.objects.deals.read
- Copy the generated access token into Private App Access Token.
- Set Enable HubSpot Sync to Yes.
- Optionally adjust the Order Status → Deal Stage Map JSON to match your HubSpot pipeline's internal stage IDs (find these under Settings → Objects → Deals → Pipelines; click a stage to see its internal ID).
Backfilling existing data
bin/magento hotchand:hubspot:resync-customers bin/magento hotchand:hubspot:resync-orders # all orders bin/magento hotchand:hubspot:resync-orders --days=90 # last 90 days only # then either wait for cron, or force an immediate run: bin/magento hotchand:hubspot:process-queue
Custom deal properties
OrderSync pushes two custom properties: magento_order_increment_id and
magento_order_status. Create these as custom properties on the Deal object
in HubSpot (Settings → Properties → Deal properties) before enabling, or
remove them from Model/Sync/OrderSync.php if you'd rather not extend the
HubSpot schema.
Notes / things to verify against current HubSpot docs before going live
- The deal↔contact association call in
HubspotClient::upsertDeal()uses the default association labeldeal_to_contact. HubSpot's association API has changed shape a few times — confirm the current default association type/label (or association type ID) in HubSpot's CRM Associations v4 docs and adjust that one call if needed. - HubSpot enforces API rate limits per account tier (typically 100–190
requests per 10 seconds, higher on paid tiers). The batch endpoints used
here keep this module well under that for most stores, but if you have a
very high order volume, consider lowering the cron frequency or increasing
batch_sizeso fewer, larger requests are made. - This module intentionally does not delete or deduplicate existing HubSpot contacts — it only upserts by email.