Customers & accounts
HubSpot CRM Sync
Indicative price, not an offer: €34/mo; credential: we maintain HubSpot API integration, daily sync
Generated from docs/plan/paid/hubspot-crm-sync/PLAN.md in the AstroBaaS repository. Nothing described below is implemented — it is the written plan for it.
HubSpot CRM Sync automatically pushes customer profiles, order history, and product interactions to HubSpot, keeping the sales team’s view in sync with ecommerce reality.
The problem
Sales team lives in HubSpot; customer data from ecommerce is manual, stale, and errors accumulate.
What it does
- OAuth flow to connect HubSpot account
- Push new customers to HubSpot as contacts
- Push orders as CRM deals or associations
- Map custom fields (store customer_id to HubSpot property)
- Daily sync of order status changes (paid, shipped, refunded)
- Pull HubSpot notes/tags back into AstroBaaS (optional reverse sync)
- Track sync status and last-sync timestamp
- Retry failed syncs with exponential backoff
- Filter which customer data to sync
- Audit log every sync attempt and payload
What it deliberately does NOT do
Each boundary carries its reason. A boundary without a reason gets crossed by the next person who reads this.
- HubSpot account creation (merchants must have HubSpot already) — reduces scope to data sync only
- Field mapping UI for all HubSpot field types (custom text/int/date only) — no file/rich-text
- Two-way customer update (HubSpot to AstroBaaS) — reduces latency/conflict; data flows ecom to CRM only
- Sync frequency < daily (HubSpot API limits) — daily minimum
- Multi-currency order line items as separate deals (one object per order) — out of scope
Data model
HubSpotConnection: store_id, access_token (encrypted), refresh_token, oauth_scope, installed_at, last_sync_at. HubSpotFieldMapping: connection_id, astrobaas_field, hubspot_property_id, field_type. HubSpotSyncLog: connection_id, entity_type, entity_id, payload (JSON), status, error_msg, synced_at. Migration: add 3 tables; encrypt tokens.
API
- POST /admin/integrations/hubspot/connect
- POST /admin/integrations/hubspot/callback
- GET /admin/integrations/hubspot/status
- POST /admin/integrations/hubspot/sync-now
- GET /admin/integrations/hubspot/field-mappings
- PATCH /admin/integrations/hubspot/field-mappings
- POST /admin/integrations/hubspot/disconnect
Every route added here must also appear in src/pages/openapi.json.ts — a test
fails the build if it does not.
Admin
Integration status card: connection state, last sync, error count. Field mapping builder: select AstroBaaS fields to HubSpot property lookup. Sync log viewer: filter by type/date, view payload and errors. Manual sync trigger. Settings: filter rules (e.g., orders > 100 EUR).
The seam — why this is paid
Core owns: customer database, order data, product/variant structure, order/customer hooks. Paid module owns: HubSpot API OAuth, field mapping UI, sync scheduling, payload templating, retry logic, token encryption.
Credential: HubSpot API key management, custom-property sync, contact dedup
Dependencies
- customer-profiles
Acceptance checks
Each of these must be able to fail. Before claiming this is done, break the code deliberately and watch each one go red.
- New customer in AstroBaaS syncs to HubSpot within 24 hours
- Changing customer email syncs email update to HubSpot within 24 hours
- Refunded order syncs with deal stage = Closed Lost
- Syncing 500 orders/day does not exceed HubSpot rate limits
- Disconnecting revokes token; re-sync fails with auth error
- Customer created before sync enabled is synced on next daily run (catch-up)
Risks
Plaintext token in logs. HubSpot API outage causes silent failures. Misconfigured field mapping causes silent failures. Duplicate contacts if deduplication wrong. last_sync_at not atomically updated.
Commercial context
| Suggested price | €34/mo; credential: we maintain HubSpot API integration, daily sync |
| Rival anchor | HubSpot: €0-3200/mo (CRM); integration fee: custom |
The anchor is what the nearest equivalent charges on Shopify or Magento today. It is context for a pricing decision, not the decision.
Generated from the commerce plan. See docs/COMMERCE-PLAN.md for the full
catalogue and ../../AI-GUIDE.md for how to work on this repository.