To integrate Salesforce with your ERP, first decide which system owns each kind of record (customers, products, prices, orders, invoices), then decide which way each one moves and how quickly. Only after that should you pick a tool: a middleware platform such as MuleSoft when several systems are involved, or a direct API connection when there are only one or two flows. Build in error queues and reconciliation from the start, and test with real volumes.
Start with ownership, not tooling
Most integration arguments are really arguments about ownership. Sales wants to edit the billing address on the account; finance insists the ERP copy is the legal one. Settle each of these in a short ownership matrix before anyone writes a mapping document. For every object, name the system that creates it, the system that may change it, and the fields that are read-only on the other side.
| Record | Usual owner | Direction | Notes |
|---|---|---|---|
| Prospects and leads | Salesforce | Stays in Salesforce | The ERP rarely needs anyone who has not bought |
| Customer account | Salesforce until first order, then shared | Salesforce to ERP on conversion; credit and terms back | Agree which address and tax fields each side may edit |
| Products and price lists | ERP | ERP to Salesforce | Salesforce needs sellable items, not every part number |
| Quotes and opportunities | Salesforce | Stays in Salesforce, or summary to ERP | Only the accepted quote usually needs to travel |
| Sales orders | ERP after submission | Salesforce creates; ERP returns status | Lock the order in Salesforce once the ERP accepts it |
| Invoices, payments, balances | ERP | ERP to Salesforce, read-only | Reps and service agents see them; they never edit them |
| Inventory and availability | ERP | Queried on demand or synced on a schedule | Consider displaying it without storing it |
Your answers may differ, and that is fine. What matters is that every row has one owner, the owner is written down, and conflicting edits have a rule. Two-way sync of the same field is the most expensive design choice in this table; accept it only when both teams genuinely need to edit that field, and define which edit wins.
Choose sync direction and timing per flow
Each row in the ownership matrix becomes one or more data flows, and each flow needs its own timing. Salesforce's architecture guidance groups integrations into process, data and virtual integrations, and separates synchronous calls, where the caller waits for an answer, from asynchronous ones, where it does not. That framing is useful when you talk to the business.
- Request and reply: a rep clicks "check credit" and waits a few seconds for the ERP to answer. Keep these to small, fast calls.
- Fire and forget: Salesforce hands off a submitted order and moves on; the ERP confirms later by updating a status.
- Scheduled batch: price lists, invoice history and balances refresh on a timetable, often overnight or hourly.
- Call-in from the ERP: the ERP (or middleware) writes shipment and invoice updates into Salesforce through its APIs or by publishing events.
- Virtual access: large or fast-changing ERP data, such as stock levels, is displayed in Salesforce when needed rather than copied into it.
Ask the business how stale each piece of data may be, in minutes or days, and how many records move at the busiest hour. Those two answers pick the timing for you far more reliably than a general preference for real time.
Middleware or point-to-point?
A point-to-point integration connects Salesforce and the ERP directly, usually with Apex callouts one way and the ERP calling Salesforce APIs the other. Middleware puts an integration platform between them that handles transformation, routing, queuing and retries. MuleSoft, which Salesforce owns, is one such platform; other integration platforms and your ERP's own connectors are alternatives worth weighing.
| Factor | Point-to-point | Middleware |
|---|---|---|
| Number of systems | Two, with little prospect of more | Three or more, or more coming |
| Upfront effort | Lower | Higher: platform setup, licensing, skills |
| Retries and queuing | You build them yourself | Provided by the platform |
| Changing one system | Every connection to it may need rework | Change is contained to that system’s adapter |
| Monitoring | Custom logs and alerts | Central dashboards across all flows |
| Who maintains it | Salesforce developers and ERP developers together | An integration team or partner that knows the platform |
A direct connection is a reasonable choice for a single, well-bounded flow, such as pushing closed orders to the ERP. Once you add a payment processor, a warehouse system and an e-commerce site, the number of direct links grows quickly and each one carries its own retry logic. That is usually the point at which a platform pays for itself.
Design for failure from day one
Every integration fails occasionally: a network timeout, an ERP maintenance window, a customer record missing a required tax code. The design question is what happens next. Salesforce's own architecture guidance notes that asynchronous patterns cannot guarantee delivery on their own, so recovery depends on retry logic you build or your middleware provides.
- Store the other system’s ID on each synced record (an external ID field in Salesforce) so updates find the right record instead of creating a new one.
- Make every write safe to repeat: use upsert on the external ID, so a retried message updates rather than duplicates.
- Send failed messages to an error queue with the payload and the reason, not just a log line.
- Alert a named person when errors pass a threshold, and give that person a way to fix and resend.
- Run a daily reconciliation that compares counts and totals, such as open orders and invoice amounts, between the two systems.
- Use a dedicated integration user with only the permissions the flows need, never a person’s login.
In one of our projects, a biotech company's administrator was re-keying payment data by hand between Salesforce, its ERP and its payment processor. We connected the three through MuleSoft with automated payment sync and error handling, and manual payment entry was eliminated. The error handling was as much a part of that result as the sync itself: without it, someone would still be checking every transfer.
Test with real data and real volumes
Build and test against a full or partial copy sandbox connected to an ERP test environment, never against production. Seed both with a realistic slice of data: customers with odd characters in their names, products with many price tiers, orders with dozens of lines. Then work through a written list of scenarios.
- The happy path for every flow, end to end, checked in both systems.
- Edits on both sides at nearly the same moment, to prove the conflict rule works.
- The ERP unavailable for an hour, followed by recovery and catch-up.
- A deliberately bad record, to confirm it lands in the error queue and can be resent.
- Peak volume: month-end invoicing or a large price-list update, timed against API limits.
- Initial load and cutover: how existing records are matched and linked before sync switches on.
Have finance and operations sign off on the reconciliation reports, not just IT. A scent-marketing manufacturer we worked with validated its new Field Service inventory flows against its ERP before a piloted rollout, which is the order we recommend: prove the numbers agree with a small group, then widen.
After go-live: ownership and change
An integration is a product, not a project. Name an owner on each side, keep the ownership matrix and field mappings in a shared place, and review error trends monthly. Salesforce releases three times a year and ERPs have upgrade cycles of their own; add integration regression tests to both release checklists so a new validation rule or renamed field does not quietly stop orders flowing. If you have already built something and it fails often, a health check of the integration layer is usually cheaper than a rebuild.
