ml-connector
Microsoft Dynamics 365 F&OSalesforce

Microsoft Dynamics 365 F&O and Salesforce integration

Microsoft Dynamics 365 F&O runs finance, procurement, and supply chain. Salesforce runs the sales and service side of the business. Connecting the two keeps the customer master and product catalog consistent so sales reps quote against accurate accounts and items, and so closed deals turn into orders in the ERP without re-keying. Customer and product records flow from Dynamics into Salesforce, while closed-won opportunities and activated orders flow back into Dynamics as sales orders. ml-connector handles the different APIs on each side and moves the data on the cadence you set.

How Microsoft Dynamics 365 F&O works

Microsoft Dynamics 365 F&O exposes customers, vendors, products, sales and purchase orders, GL accounts, and journals through a single OData v4 REST service at a tenant-specific host such as contoso.operations.dynamics.com/data/. Every call uses a Microsoft Entra ID OAuth 2.0 bearer token obtained with the client-credentials flow against the environment scope, and there is no shared base URL, so the environment host is a per-customer credential. Reads use server-driven paging up to 10,000 records with an odata.nextLink, and entity keys must be fully specified, including the dataAreaId legal entity. Dynamics can push outbound Business Events over HTTPS, but those payloads are lightweight stubs that carry a ControlNumber and identifiers, so a follow-up OData read is needed to get the full record.

How Salesforce works

Salesforce exposes Accounts, Contacts, Opportunities, Orders, Products, and Leads through its REST API on the org My Domain URL, versioned per request at v63.0. Authentication uses the OAuth 2.0 client-credentials flow against the My Domain token endpoint, and the connector must read the instance_url from the token response rather than hardcoding it. Writes can be made idempotent by upserting against an External ID field, which creates or updates by your ERP key. Salesforce publishes real-time change events through Change Data Capture over the Pub/Sub API, with a 72-hour replay window, and SOQL queries page through a nextRecordsUrl until done is true.

What moves between them

Customer and product reference data flows from Microsoft Dynamics 365 F&O into Salesforce. ml-connector reads CustomersV3 and ReleasedProducts and upserts them as Salesforce Accounts and Product2 records, keyed on the Dynamics account number and item number held in a Salesforce External ID field. In the other direction, closed-won Opportunities and activated Orders flow from Salesforce into Dynamics as sales orders, and any new account created in Salesforce can be written back as a Dynamics customer once its legal entity and currency are resolved. Cadence is event-driven where Dynamics Business Events and Salesforce Change Data Capture are enabled, with a scheduled OData and SOQL poll as the backfill so nothing is missed.

How ml-connector handles it

ml-connector stores both credential sets encrypted and mints two tokens: an Entra ID client-credentials token scoped to the Dynamics environment host, and a Salesforce client-credentials token against the org My Domain URL, refreshing each when a call returns 401. It accepts the full Dynamics environment host per customer because there is no shared base address, and it derives the Salesforce base URL from the instance_url in the token response so an org migration does not break the connection. Every Dynamics OData key is fully specified with its dataAreaId, and writes into Salesforce use External ID upserts so re-running a sync never duplicates an Account or Product2. Where Dynamics Business Events are active, the connector treats the pushed payload as a stub and calls back to OData by the supplied identifiers for the full record, deduplicating on the ControlNumber. Salesforce change events are consumed through Change Data Capture, and because that stream only retains 72 hours, the scheduled SOQL and OData poll backfills any gap. Dynamics returns HTTP 429 with a Retry-After header and Salesforce enforces a daily request limit, so the connector honors Retry-After, backs off, and retries. Legal entity and currency are mapped first so every order and customer lands on a valid Dynamics dataAreaId, and 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 maker, roughly 300 staff, runs Microsoft Dynamics 365 F&O for finance, inventory, and order fulfillment, and its sales team works deals in Salesforce. Before the integration, reps quoted from a spreadsheet of accounts and part numbers that drifted out of date, and when a deal closed an order entry clerk re-typed the customer and line items into Dynamics, introducing typos and shipping delays. With the two systems connected, the customer master and released product list sync from Dynamics into Salesforce so reps always quote against live accounts and items, and a closed-won opportunity becomes a Dynamics sales order automatically. The duplicate data entry is gone and orders reach fulfillment the same day they close.

What you can do

  • Upsert Microsoft Dynamics 365 F&O customers into Salesforce Accounts keyed on the Dynamics account number.
  • Sync Dynamics released products into Salesforce Product2 records so reps quote against live items.
  • Turn closed-won Salesforce Opportunities and activated Orders into Dynamics sales orders.
  • Bridge the Microsoft Entra ID client-credentials token and the Salesforce client-credentials token on every call.
  • Consume Dynamics Business Events and Salesforce Change Data Capture, with a scheduled poll as backfill and a full audit trail.

Questions

Which direction does data move between Microsoft Dynamics 365 F&O and Salesforce?
Customer accounts and products move from Dynamics into Salesforce so the sales team works against the ERP master. Closed-won opportunities and activated orders move from Salesforce back into Dynamics as sales orders. New Salesforce accounts can also be written back to Dynamics as customers once legal entity and currency are resolved.
How are duplicate records avoided when the same sync runs twice?
Salesforce supports idempotent writes through External ID upserts, so ml-connector keys each Account and Product2 on its Dynamics account number or item number. Re-running a sync updates the existing record instead of creating a new one. Dynamics OData has no idempotency header and uses natural keys, so the connector specifies the full key, including dataAreaId, and deduplicates Business Events on their ControlNumber.
Does the integration use webhooks or polling?
It uses both. Dynamics can push lightweight Business Events over HTTPS and Salesforce streams changes through Change Data Capture over the Pub/Sub API, and ml-connector consumes both as they arrive. Because Dynamics event payloads are stubs and the Salesforce change stream only retains 72 hours, a scheduled OData and SOQL poll runs as a backfill so no record is missed.

Related integrations

Connect Microsoft Dynamics 365 F&O and Salesforce

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

Get started