HubSpot Integration
MIDDAG Account integrates with HubSpot as the CRM layer. HubSpot tracks the sales process -- deals, quotes, contacts, and companies. Billing and payment happen in WooCommerce and Stripe. HubSpot tracks revenue, not transactions.
Dual-account architecture
| Account | Legal entity | Market | Currency |
|---|---|---|---|
| HubSpot BR | MIDDAG Tecnologia LTDA | Brazil | BRL |
| HubSpot LLC | MIDDAG, LLC | International | USD |
Each account has its own access token, portal ID, and webhook endpoint. The same client organization can exist in both HubSpots, linked through the plugin's Organization record.
Setup
API credentials
Configure in your environment or wp-config.php:
| Variable | Description |
|---|---|
HUBSPOT_BR_ACCESS_TOKEN | Access token for HubSpot BR |
HUBSPOT_BR_PORTAL_ID | Portal ID for HubSpot BR |
HUBSPOT_LLC_ACCESS_TOKEN | Access token for HubSpot LLC |
HUBSPOT_LLC_PORTAL_ID | Portal ID for HubSpot LLC |
Webhook endpoints
Register these URLs in HubSpot under Settings > Integrations > Webhooks:
| Account | Webhook URL |
|---|---|
| HubSpot BR | https://yoursite.com/wp-json/middag-account/v1/webhooks/hubspot/br |
| HubSpot LLC | https://yoursite.com/wp-json/middag-account/v1/webhooks/hubspot/llc |
Deal pipelines
Configure these pipelines in each HubSpot account:
| Pipeline | Channel | Flow |
|---|---|---|
self-serve | WooCommerce / Stripe | Automatic: purchase triggers deal closed-won |
consultative | HubSpot managed | Manual: sales rep manages deal stages |
renewal | Automatic | Automatic: renewal events update deals |
upsell | HubSpot managed | Manual: CS team manages upgrade opportunities |
Organization-to-Company mapping
Each organization in the plugin stores two HubSpot company IDs:
| Field | Description |
|---|---|
hubspot_company_id_br | Company ID in HubSpot BR |
hubspot_company_id_global | Company ID in HubSpot LLC |
The plugin is the deduplication point. When the same client exists in both HubSpots, their single Organization record holds both company IDs.
Source of truth by field
Sync happens at the field level, not the entity level. Each field has a defined owner:
| Data | Source of truth | Direction |
|---|---|---|
| Organization fields | Plugin | Plugin to HubSpot |
| Deals and pipeline stages | HubSpot | HubSpot to Plugin |
| Quote status (accepted/paid) | Plugin | Plugin to HubSpot |
| Quote creation data | HubSpot | HubSpot to Plugin |
| Contact commercial data | HubSpot | HubSpot to Plugin |
| Order/payment status | Plugin | Plugin to HubSpot |
When a conflict is detected (field edited in both systems), the plugin wins for organization data. An audit trail records the field, old value, new value, and which source prevailed.
Quote flow
The quote lifecycle spans both systems:
Each quote belongs to a billing entity (BR or Global). The sync targets the correct HubSpot account.
Webhook events
Deals
| Event | Plugin action |
|---|---|
deal.creation | Register opportunity locally |
deal.propertyChange (stage) | Update local stage, amount, close date |
deal.deletion | Mark deal as removed |
Quotes
| Event | Plugin action |
|---|---|
quote.creation | Create Quote (status: draft) |
quote.propertyChange | Update local quote |
quote.deletion | Mark quote as cancelled |
Contacts
| Event | Plugin action |
|---|---|
contact.creation | Create or update linked contact |
contact.propertyChange | Update contact data |
contact.deletion | Deactivate contact |
HubSpot custom properties
The following custom properties should be created on HubSpot products for correct sync:
| Property | Source | Purpose |
|---|---|---|
middag_sku | Product SKU | Links HubSpot product to YAML |
middag_tier | Product tier | Reporting by funnel tier |
middag_entitlement_class | Entitlement class | Provisioning routing |
middag_billing_model | Billing model | Revenue type classification |
middag_brand | Brand | Multi-brand reporting |
Synced services
The integration uses seven service classes, migrated from the original theme:
| Service | Function |
|---|---|
| CompanyService | Sync Organization with HubSpot Company |
| ContactService | Sync Collaborator to HubSpot Contact |
| DealService | Read HubSpot deals for admin display |
| QuoteService | Bidirectional quote sync |
| AssociationService | Link company, contact, and deal records |
| SearchService | Search companies and contacts in HubSpot |
| LineItemService | Sync quote line items |
Deal isolation
Deals in HubSpot BR stay in HubSpot BR. Deals in HubSpot LLC stay in HubSpot LLC. There is no cross-sync between accounts. The plugin reads deals from both accounts for display in the admin UI (read-only).
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Organization not syncing | Missing HubSpot company ID | Verify the organization has a company ID set |
| Quote status not updating | Webhook signature validation | Confirm HMAC secret is correct per account |
| Duplicate contacts in HubSpot | Dedup not running | Check that organization links both accounts |
| Deal data stale | Webhook endpoint not registered | Register the endpoint in HubSpot settings |