ml-connector
Microsoft Dynamics 365 F&OHubSpot

Microsoft Dynamics 365 F&O and HubSpot integration

Microsoft Dynamics 365 F&O runs finance, customers, and order processing. HubSpot runs the CRM where sales teams work contacts, companies, and deals. Connecting the two keeps the customer and product masters in agreement and lets a closed-won deal become a real customer and sales order in the ERP without re-keying. ml-connector handles the different APIs and auth on each side and moves records on a schedule you control. Because HubSpot is a CRM and has no general ledger, the GL and posted financials stay in Dynamics where they belong.

How Microsoft Dynamics 365 F&O works

Microsoft Dynamics 365 F&O exposes customers, vendors, products, purchase orders, vendor invoices, GL accounts, and financial dimensions through an OData v4 REST service at a tenant-specific host such as contoso.operations.dynamics.com. It authenticates with OAuth 2.0 client credentials issued by Microsoft Entra ID, and entity keys must be fully specified, including dataAreaId for the legal entity. It pushes outbound Business Events over HTTPS, but those payloads carry only identifiers and a ControlNumber, so the handler must call back to OData for full record detail. There is no shared base URL, so the environment host is a credential field.

How HubSpot works

HubSpot exposes contacts, companies, deals, products, line items, invoices, and payments through its REST CRM API at api.hubapi.com, on date-versioned paths such as /crm/objects/2026-03 alongside the still-active /crm/v3 paths. A server-to-server integration uses a Private App access token, beginning with pat-, passed as a Bearer header and scoped to the objects it touches. Reads are cursor-paged with after and limit up to 200, and the batch upsert endpoint matches on an idProperty so a re-run updates rather than duplicates. Webhook subscriptions require a separate Public OAuth app, and invoice write entered public beta in January 2026.

What moves between them

Master data flows from Microsoft Dynamics 365 F&O into HubSpot: customers become HubSpot companies and contacts, and released products become HubSpot products, so sales teams quote against records that exist in the ERP. Closed-won deals flow the other way, where ml-connector creates or updates the matching customer in Dynamics and opens a sales order for fulfillment and invoicing. Product and customer references are aligned on both sides so each deal line resolves to a real Dynamics product number and customer account. The general ledger and posted invoices stay in Dynamics, since HubSpot has no GL, so ml-connector never writes ledger entries into the CRM.

How ml-connector handles it

ml-connector stores both credential sets encrypted. On the Dynamics side it requests an Entra ID bearer token with the client credentials flow against the tenant-specific scope and refreshes it when a call returns 401, and it fully specifies entity keys including dataAreaId, adding cross-company for multi-entity reads. On the HubSpot side it sends the Private App token as a Bearer header and writes companies, contacts, and products through the batch upsert endpoint, matching on a stable external id such as the Dynamics customer account so a re-read does not create duplicates. It polls Dynamics customers and products on a schedule and can take a Dynamics Business Event over HTTPS as a trigger, deduping on the ControlNumber and then calling back to OData for the full record because the event is only a stub. Both APIs return HTTP 429 with Retry-After, so ml-connector backs off and retries, and a HubSpot Private App alone cannot receive webhooks, so HubSpot-side change capture is handled by polling or a separate Public app. Financial dimensions are passed as the formatted display string Dynamics expects, mapped from the deal context first so postings land on valid accounts. Every record carries a full audit trail and can be replayed if a downstream call fails.

A real-world example

A mid-sized industrial equipment distributor, around 300 employees, runs Microsoft Dynamics 365 F&O for finance and order processing and HubSpot as the CRM for its sales reps. Before the integration, a rep closed a deal in HubSpot and then a finance clerk re-keyed the customer and order into Dynamics by hand, so customers were entered twice with mismatched names, product codes were sometimes wrong, and orders sat for a day before fulfillment saw them. With Microsoft Dynamics 365 F&O and HubSpot connected, the ERP customer and product masters sync into HubSpot so reps quote against real records, and each closed-won deal opens a Dynamics customer and sales order within the polling window. The duplicate-entry and miskeyed-product problems are gone, and orders reach fulfillment the same day they close.

What you can do

  • Sync Microsoft Dynamics 365 F&O customers and products into HubSpot companies, contacts, and products.
  • Turn closed-won HubSpot deals into Dynamics customer and sales order records for fulfillment.
  • Match HubSpot upserts on a stable external id so a re-read never creates duplicate companies or products.
  • Bridge Entra ID OAuth client credentials on Dynamics with the HubSpot Private App access token.
  • Poll on a schedule with Business Event triggers, 429 backoff, and a full audit trail on every record.

Questions

Which direction does data move between Microsoft Dynamics 365 F&O and HubSpot?
Master data moves from Dynamics into HubSpot, where customers become companies and contacts and products become HubSpot products. Closed-won deals move the other way and create a customer and sales order in Dynamics. HubSpot has no general ledger, so posted invoices and GL entries stay in Dynamics and ml-connector never writes ledger data into the CRM.
Does Dynamics push changes, or does ml-connector poll for them?
Both are supported. ml-connector polls Dynamics customers and products on a schedule, and where Business Events are activated it can take an HTTPS push as a trigger. Because a Business Event payload carries only identifiers and a ControlNumber, ml-connector dedupes on that number and then calls back to the OData service to retrieve the full record before syncing.
How does the integration avoid duplicate records in HubSpot?
HubSpot has no universal idempotency header, so ml-connector writes companies, contacts, and products through the batch upsert endpoint, which matches on an idProperty. It keys that match on a stable external id such as the Dynamics customer account, so re-reading the same Dynamics record updates the existing HubSpot record instead of creating a second one.

Related integrations

Connect Microsoft Dynamics 365 F&O and HubSpot

Free to use. Add your credentials, ping your real systems, and see if we fit.

Get started