Skip to main content

HubSpot ↔ Acumatica Sync Guide

Bi-directional data synchronization between HubSpot CRM and Acumatica ERP.

Architecture

Acumatica (ERP)
↕ REST API (15-min cron)
webhook-router (BullMQ workers)
↕ REST API + Webhooks
HubSpot (CRM)

All sync runs through the webhook-router service on Railway, using BullMQ queues backed by Redis.

Sync Paths

PathDirectionScheduleDedup Key
Customers → CompaniesAcumatica → HubSpot15-min cronacumatica_customer_id
Customers → ContactsAcumatica → HubSpot15-min cronemail (quality gated)
StockItems → ProductsAcumatica → HubSpot15-min cronacumatica_inventory_id
SalesOrders → OrdersAcumatica → HubSpot15-min cronhs_external_order_id
Order Details → Line ItemsAcumatica → HubSpot15-min cronacumatica_line_key
Cases → TicketsBi-directional10-min cron + webhookacumatica_case_id

Sync Phases

Each sync cycle follows a 3-phase pattern:

  1. Phase 1: Fetch — Query Acumatica entities modified since last sync (session gate coordinated)
  2. Phase 2: Push — Upsert records to HubSpot (no Acumatica session needed)
  3. Phase 3: Write-Back — Write HubSpot record IDs back to Acumatica attributes (session gate coordinated)

Company Properties Synced

HubSpot PropertyAcumatica Source
nameCustomerName
phoneMainContact.Phone1
address, city, state, zip, countryMainContact.Address.*
acumatica_customer_idCustomerID
acumatica_credit_limitCreditLimit
acumatica_payment_termsTerms
acumatica_account_balanceCreditVerificationRules balance
acumatica_customer_classCustomerClass
acumatica_salespersonSalespersons[].Default
acumatica_ship_viaShipVia

Write-Back (HubSpot → Acumatica)

After successful HubSpot upserts, the sync writes HubSpot record IDs back to Acumatica:

Acumatica AttributeHubSpot SourceMethod
HUBSPOTPID (StockItem)Product IDAttribute write
HUBSPOTCID (Customer)Company IDAttribute write
UsrHubSpotDealId (SalesOrder)Order IDDAC UDF write
HUBSPOTTID (Case)Ticket IDAttribute write

Echo Prevention

For bi-directional sync (Cases ↔ Tickets), Redis lock keys prevent echo loops:

  • case-sync:lock:{caseCD} — 120s TTL after Acumatica → HubSpot sync
  • case-sync:lock:ticket:{ticketId} — 120s TTL after HubSpot → Acumatica sync

Transform Functions

Key transform functions in acumatica-transform.ts:

  • val(field) — Unwraps {value: x} → raw value
  • str(field) — Unwraps to string
  • toDateStr(field) — Converts to epoch ms string for HubSpot
  • extractBalance(record) — Reads from CreditVerificationRules with fallback
  • extractDefaultSalesperson(record) — Finds default from Salespersons[] array

Debugging

Check sync status

GET /sync/status

Force a sync cycle

POST /sync/trigger

View sync logs

Check Railway logs for the webhook-router service. Filter by [sync] prefix.