Salesforce ERP Integration Guide | SalesforceTutorial

Written by Prasanth Kumar Published on Updated on

Salesforce ERP Integration Guide

Salesforce ERP usually means Salesforce connected to an enterprise resource planning system, not Salesforce replacing the ERP. In most production orgs, Salesforce owns customer-facing work such as leads, opportunities, quotes, cases, and partner portals, while the ERP owns finance, fulfillment, inventory, procurement, tax, and accounting records.

The right question is not only is Salesforce an ERP system. The better design question is which system owns each record, which users need the data, and whether Salesforce ERP integration should use middleware, APIs, events, external objects, Flow, or Apex.

What is Salesforce ERP in implementation work?

In implementation language, Salesforce ERP is a shorthand for a connected architecture where Salesforce users can act on ERP-backed information without logging into the ERP for every step. A sales rep may view credit status before submitting a quote. A service agent may see shipped assets and warranty dates. A finance user may receive an approved order from Salesforce and continue invoicing in the ERP.

Salesforce provides CRM applications and a metadata-driven platform. ERP products handle enterprise operations such as general ledger, accounts receivable, manufacturing, procurement, stock movement, and statutory reporting. Salesforce can store selected ERP data, expose ERP data through external objects, or call ERP APIs during a process. It should not become the accounting subledger unless the business has deliberately built and governed that model.

Is Salesforce an ERP system?

Is Salesforce an ERP system? No, not in the usual enterprise architecture sense. Salesforce is primarily CRM and platform software. It can support order capture, service, field operations, revenue workflows, and custom business objects, but a true ERP remains the system of record for accounting, inventory valuation, procurement, manufacturing, and financial close in most orgs.

The answer to is Salesforce an ERP system can change only if an organization builds custom ERP-like processes on Salesforce and accepts the governance, audit, data model, and compliance work that comes with that decision. In enterprise orgs, that approach is uncommon for core finance because ERP systems already contain tested controls for accounting and operations.

How to answer is Salesforce an ERP system in workshops

In stakeholder workshops, treat is Salesforce an ERP system as a scope question. If sales asks is Salesforce an ERP system, explain that Salesforce can start the commercial process but the ERP usually completes operational and financial posting. If finance asks is Salesforce an ERP system, confirm that general ledger, invoice posting, tax, and payment clearing remain ERP responsibilities unless an approved architecture decision says otherwise.

For admin and developer teams, the phrase is Salesforce an ERP system should trigger a system-of-record discussion. A Salesforce ERP roadmap can include ERP data visibility, ERP API calls, and ERP status reporting, but the Salesforce ERP boundary must be written into the design before objects and fields are built.

Capability Salesforce usually owns ERP usually owns Integration design note
Customer engagement Lead, Account, Contact, Opportunity, Case Customer master reference Use external IDs so both systems agree on customer identity.
Product selling Product selection, quote preparation, approvals Item master, availability, pricing rules, tax, fulfillment Keep the pricing source clear; do not let two systems calculate final price differently.
Order to cash Order request, customer status visibility Sales order, shipment, invoice, payment, credit memo ERP order number should flow back to Salesforce for support and reporting.
Service Case, entitlement, asset view, field service appointment Installed base source, warranty, replacement part movement Agents need enough ERP context to resolve the case without editing finance records.

How to plan a Salesforce ERP project before building

A Salesforce ERP project fails when the team starts with connectors instead of process ownership. Start with business events: quote submitted, order accepted, shipment posted, invoice created, payment received, item blocked, credit limit exceeded, and case escalated. Then decide whether Salesforce must create, read, update, or only display the ERP record.

Use measurable outcomes, but avoid borrowed benchmark numbers. Your baseline should come from your org. For example, if quote approval takes six business days because users wait for stock and credit checks, measure that delay before and after the integration.

Process Baseline metric System interaction Owner to confirm
Quote approval Time from quote draft to approved quote Salesforce asks ERP for price, tax, inventory, and credit status Sales operations and finance
Order submission Orders rejected because of missing or invalid data Salesforce sends approved order payload to ERP Sales operations and ERP owner
Case resolution Time spent asking operations for shipment or invoice status Salesforce displays ERP shipment, invoice, and asset data Service operations
Receivables follow-up Open invoices reviewed by account owner ERP publishes invoice and payment status to Salesforce Finance

Salesforce ERP data ownership: what should sync?

Data ownership is the design control for every Salesforce ERP build. Write it down before object mapping. A field can be visible in Salesforce without being editable there. A record can be created in Salesforce but finalized in ERP. A status can be copied into Salesforce for reporting, while all financial posting remains in ERP.

Master data mapping

Master data changes less often than transactions, but bad master data breaks every downstream flow. For Salesforce ERP integration, treat customer, product, price book, address, currency, payment term, tax, and territory data as governed data. Pick a system of record for each field, not only each object.

Salesforce record ERP record Common direction Design rule
Account Customer or business partner Often bidirectional before finance approval, then ERP controlled Store ERP customer number as an External ID field in Salesforce.
Contact Contact person Bidirectional, with duplicate matching rules Define which system can merge or delete contacts.
Product2 Item or material master Usually ERP to Salesforce Use product code as the stable integration key when possible.
PricebookEntry Price list or condition record Usually ERP to Salesforce or calculated on demand Do not copy every pricing condition if ERP must calculate final price.

Transactional data mapping

Transactions need stronger controls than master data because they create financial or operational commitments. A Salesforce ERP design should separate draft intent from posted transaction. Salesforce can capture intent; ERP should confirm whether the order exists, whether it was accepted, and what number the ERP assigned.

Salesforce data ERP data Typical direction Implementation note
Quote Quotation or order proposal Salesforce to ERP, with ERP validation response Persist the request payload and response status for audit.
Order Sales order Salesforce to ERP, then ERP status back to Salesforce Use idempotency keys to prevent duplicate ERP orders after retries.
Invoice__c custom object or external object Invoice ERP to Salesforce or live read Make invoice records read-only for sales and service users unless finance approves edits.
Payment__c custom object or external object Payment or clearing document ERP to Salesforce Show open/paid status, but keep posting logic in ERP.
Asset Installed base, equipment, serial number ERP to Salesforce, with service updates as needed Define whether replacement and de-installation can start from Service Cloud.

Is Salesforce an ERP system when custom objects store ERP data?

Is Salesforce an ERP system if you create custom objects for invoices, payments, inventory, or assets? Usually no. Custom objects can mirror ERP data for visibility and reporting. They do not automatically provide ERP controls such as posting periods, inventory valuation, procurement approvals, or financial close. Treat mirrored records as operational views unless the business formally moves ownership to Salesforce.

Salesforce ERP integration patterns for 2026 orgs

The best pattern depends on volume, latency, data ownership, error recovery, and licensing. A small customer credit check can run differently from a nightly product load or a high-volume invoice feed. Use official Salesforce APIs and platform features rather than direct database access to Salesforce.

Salesforce ERP integration: pattern choices

Pattern Use it when Salesforce feature or doc Watch for
Middleware or API-led integration Several systems need orchestration, mapping, retries, and monitoring MuleSoft Anypoint Connector for Salesforce Do not hide data ownership rules inside middleware only; document them in the architecture.
REST API or Composite API An ERP or middleware needs to create or update Salesforce records through HTTPS Composite REST API Validate partial success behavior and retry only failed units.
Bulk API 2.0 Large scheduled loads such as product, price, invoice, or historical data Bulk API 2.0 Plan for batch monitoring, failed record files, and reconciliation.
Platform Events Salesforce and ERP processes need event-based handoff Platform Events Events are not a full data store; design replay, error, and recovery logic.
Change Data Capture External subscribers need to react to Salesforce record changes Change Data Capture Confirm supported objects, event retention, and downstream replay strategy.
Salesforce Connect Users need live ERP data in Salesforce without copying all records Salesforce Connect Check OData performance, licensing, search behavior, and offline needs.
Flow HTTP Callout A declarative process must call an external REST endpoint Flow HTTP Callout Keep complex mapping and retry handling out of a record-triggered flow when the transaction is critical.
Apex callout You need code-level control over payloads, retries, idempotency, or custom validation Apex callouts Respect callout limits, bulkification, test mocks, and transaction boundaries.

For most enterprise builds, Salesforce ERP integration uses more than one pattern. Example: MuleSoft loads Products and Prices nightly, Salesforce Connect displays live inventory, a Queueable Apex job submits approved quotes, and Change Data Capture sends account updates to the ERP master data service.

How to design Salesforce ERP integration step by step

  1. Confirm the business event. Name the event in business language, such as Quote Approved or Invoice Posted. Do not start with field mapping.
  2. Choose the record owner. For each object and field, mark Salesforce, ERP, or shared ownership with conflict rules.
  3. Define external IDs. Add fields such as ERP_Customer_Id__c, ERP_Order_Number__c, and ERP_Last_Sync_At__c. Use External ID and Unique where the data model allows it.
  4. Choose sync timing. Use real-time only when the user must wait for the answer. Use scheduled or event-based sync for reporting and operational visibility.
  5. Design error states. Use statuses such as Pending ERP, Accepted by ERP, Rejected by ERP, and Retry Required. Give users a reason code, not only a failed checkbox.
  6. Plan retries safely. Include an idempotency key, correlation ID, and payload hash. The ERP should reject duplicate order creation but accept a retry of the same request.
  7. Build observability. Store request time, response time, endpoint, status code, message, and owning record. This makes support possible after go-live.
  8. Test with production-like data. Use a Salesforce sandbox and an ERP non-production tenant. Include tax, currency, inactive products, blocked customers, and partial shipment cases.

Apex example for Salesforce ERP quote sync

This Apex example sends approved Salesforce Quotes to an ERP endpoint through a Named Credential. It uses Queueable Apex with Database.AllowsCallouts so the callout runs outside the user save transaction. It sends one batched request for the quote set instead of making a callout inside a loop.

Before using this pattern, create a Named Credential and External Credential for the ERP endpoint. Salesforce documents Named Credentials as a way to define the callout endpoint and authentication settings outside Apex code. Flow HTTP Callout also expects a Named Credential when it authenticates to an external system.

public with sharing class ErpQuoteSyncService {
    public class ErpQuoteSyncException extends Exception {}

    public static void enqueue(Set<Id> quoteIds) {
        if (quoteIds == null || quoteIds.isEmpty()) {
            return;
        }
        System.enqueueJob(new QuoteSyncJob(quoteIds));
    }

    public class QuoteSyncJob implements Queueable, Database.AllowsCallouts {
        private Set<Id> quoteIds;

        public QuoteSyncJob(Set<Id> quoteIds) {
            this.quoteIds = new Set<Id>(quoteIds);
        }

        public void execute(QueueableContext context) {
            List<Quote> quotes = [
                SELECT Id, QuoteNumber, GrandTotal, AccountId, Status,
                    (SELECT Id, Quantity, UnitPrice,
                            PricebookEntry.Product2.ProductCode
                     FROM QuoteLineItems)
                FROM Quote
                WHERE Id IN :quoteIds
            ];

            List<QuotePayload> payloads = new List<QuotePayload>();

            for (Quote q : quotes) {
                QuotePayload payload = new QuotePayload();
                payload.salesforceQuoteId = (String) q.Id;
                payload.quoteNumber = q.QuoteNumber;
                payload.accountId = (String) q.AccountId;
                payload.status = q.Status;
                payload.totalAmount = q.GrandTotal;
                payload.lines = new List<LinePayload>();

                for (QuoteLineItem line : q.QuoteLineItems) {
                    LinePayload linePayload = new LinePayload();
                    linePayload.productCode =
                        line.PricebookEntry.Product2.ProductCode;
                    linePayload.quantity = line.Quantity;
                    linePayload.unitPrice = line.UnitPrice;
                    payload.lines.add(linePayload);
                }

                payloads.add(payload);
            }

            HttpRequest request = new HttpRequest();
            request.setEndpoint('callout:ERP_Named_Credential/api/v1/salesforce/quotes');
            request.setMethod('POST');
            request.setHeader('Content-Type', 'application/json');
            request.setTimeout(60000);
            request.setBody(JSON.serialize(payloads));

            HttpResponse response = new Http().send(request);
            Integer statusCode = response.getStatusCode();

            if (statusCode < 200 || statusCode >= 300) {
                throw new ErpQuoteSyncException(
                    'ERP quote sync failed. Status=' + statusCode +
                    ', Body=' + response.getBody()
                );
            }
        }
    }

    public class QuotePayload {
        public String salesforceQuoteId;
        public String quoteNumber;
        public String accountId;
        public String status;
        public Decimal totalAmount;
        public List<LinePayload> lines;
    }

    public class LinePayload {
        public String productCode;
        public Decimal quantity;
        public Decimal unitPrice;
    }
}

Production notes for this Salesforce ERP code:

  • The sample assumes Quotes and Quote Line Items are enabled, and that the ERP accepts a batch of quote payloads.
  • Do not call ErpQuoteSyncService.enqueue once per record from a trigger. Collect IDs and enqueue once for the trigger context.
  • A single Apex transaction can make a maximum of 100 callouts. The example uses one callout for the batch, which leaves room for future validation calls.
  • For high-volume order submission, use a staging object and a scheduled Queueable or Batch Apex process instead of sending every user save directly to ERP.
  • Do not store client secrets, tokens, or ERP passwords in custom settings or custom metadata. Use Named Credentials and External Credentials.

Test mock for ERP callouts

Apex tests cannot make real HTTP callouts. Use HttpCalloutMock, create the Salesforce test data, call Test.setMock, then execute the Queueable inside Test.startTest() and Test.stopTest(). Salesforce requires at least 75% Apex code coverage for deployment, but coverage alone is not enough; assert the endpoint, method, payload, and error handling.

@IsTest
private class ErpQuoteSyncServiceMock implements HttpCalloutMock {
    public HTTPResponse respond(HTTPRequest request) {
        System.assertEquals('POST', request.getMethod());
        System.assert(
            request.getEndpoint().startsWith('callout:ERP_Named_Credential')
        );

        HttpResponse response = new HttpResponse();
        response.setStatusCode(202);
        response.setBody('{"accepted":true}');
        return response;
    }
}

How Flow fits into Salesforce ERP integration

Flow can handle a focused Salesforce ERP integration use case when the API contract is simple and the business process belongs in Flow. For example, a screen flow can check product availability after a user selects a product, or an autolaunched flow can call a shipping quote API after required fields are complete.

Flow HTTP Callout is generally available in Salesforce documentation since Summer ’23 release notes. Use it for clear request-response actions. Do not use record-triggered flow as a hidden integration engine for complex order creation, multi-step compensation, or high-volume retries. In those cases, put the orchestration in middleware, Apex, or an event-driven design.

How Salesforce Connect helps with ERP visibility

Salesforce Connect lets users view, search, and interact with data stored outside the org through external data sources and external objects. This pattern helps when users need ERP invoice, inventory, shipment, or asset data in Salesforce but the business does not want to copy and store every ERP row.

Use Salesforce Connect when freshness matters more than local reporting or automation. Use copied custom objects when Salesforce reports, dashboards, sharing, automation, offline behavior, or history tracking must run on the data. A good Salesforce ERP architecture can use both: external objects for live invoice lookup and nightly copied summary records for account health reporting.

Security, limits, and testing for Salesforce ERP integration

Security problems in Salesforce ERP integration usually come from over-permissioned integration users, bypassed field-level security, or users seeing ERP data that they should not see. Treat integration access like production finance access. Grant the minimum object, field, and API permissions needed for the integration path.

Security controls to apply

  • Use an integration user where appropriate. Salesforce documents an Integration user license and API-only access pattern for machine-to-machine integrations.
  • Use Connected Apps and API access control. Approve the client that calls Salesforce APIs and avoid broad API access for users who do not need it.
  • Separate authentication from code. Store endpoint and authentication details in Named Credentials and External Credentials.
  • Respect sharing and data access. with sharing enforces record sharing, but sharing declarations do not enforce object CRUD or field-level security by themselves.
  • Enforce CRUD and FLS in Apex. Use user-mode database operations or Security.stripInaccessible where user permissions should control visible or writable data.
List<Account> accounts = [
    SELECT Id, Name, ERP_Customer_Id__c
    FROM Account
    WHERE Id IN :accountIds
    WITH USER_MODE
];

SObjectAccessDecision decision = Security.stripInaccessible(
    AccessType.UPDATABLE,
    accounts
);
List<SObject> recordsSafeToUpdate = decision.getRecords();

Governor limits and integration limits

Governor limits must shape the design. Apex callouts have limits, including the maximum number of callouts in one transaction. API-based integrations must also account for Salesforce API limits, middleware limits, ERP rate limits, and endpoint timeouts. A Salesforce ERP integration should batch where possible, retry safely, and fail with a supportable error record instead of leaving users to guess.

  • Never make one HTTP callout per line item in a trigger.
  • Use Composite API when an external client needs to reduce round trips to Salesforce.
  • Use Bulk API 2.0 for large imports or updates instead of REST one record at a time.
  • Use Platform Events or Change Data Capture when systems need to react to changes asynchronously.
  • Keep ERP timeout behavior clear. A timeout does not prove failure; it means the caller did not receive a response.

Common errors with Salesforce ERP projects

Error Why it happens Fix
No stable external ID The team maps records by name, email, or product description Use ERP IDs and Salesforce IDs as stored integration keys; make keys unique where possible.
Duplicate ERP orders A retry creates a new order because the ERP cannot identify the original request Send an idempotency key and store the ERP response against the Salesforce record.
Conflicting price calculations Salesforce and ERP both calculate price, discount, tax, or freight differently Choose the pricing authority. If ERP is authority, Salesforce should request calculated values or store approved snapshots.
Hidden integration failures Errors appear only in debug logs or middleware logs Create an Integration_Log__c object or use a monitored logging service with correlation IDs.
Over-permissioned integration user The project uses System Administrator because it is faster during build Create a permission set for the integration path and review it before go-live.
Wrong answer to is Salesforce an ERP system The org copies ERP records into Salesforce and assumes ownership moved automatically Document whether each copied record is a read-only mirror, a workflow object, or the official system of record.

Best practices for Salesforce ERP integration

  • Start with a system-of-record matrix. Put Account, Product, Price, Order, Invoice, Payment, Inventory, Asset, and Case on one page with owner, direction, timing, and error owner.
  • Use event names, not only object names. A field update is not always an ERP event. For example, Quote Approved is a clearer integration trigger than Quote Updated.
  • Keep financial posting in ERP unless there is a formal architecture decision. Salesforce can show finance data without becoming the finance system.
  • Version the integration contract. Treat payload fields, enum values, required fields, and response codes as an API contract.
  • Build for partial failure. An ERP can accept the header and reject one line. Decide how Salesforce users see and repair that state.
  • Use sandboxes and ERP test tenants. Test blocked customers, inactive products, credit holds, tax edge cases, different currencies, duplicate retries, and partial shipments.
  • Document support ownership. A failed integration record needs a queue, owner, runbook, and escalation path.

When should you build Salesforce ERP integration?

Build Salesforce ERP integration when users make decisions in Salesforce that depend on ERP data, or when ERP users need clean customer-facing data from Salesforce. Do not integrate every object by default. Copying data increases storage, security review effort, reconciliation work, and failure scenarios. Keep each Salesforce ERP decision tied to a named business event and a record owner, and keep Salesforce ERP integration scope small enough to test.

A practical first release often includes customer identity, product availability, approved quote or order submission, ERP order status, invoices, and assets. Later releases can add payments, returns, credit memos, advanced pricing, procurement visibility, and finance analytics. This phased approach lets the team learn from production data without forcing every department into one release.

Official Salesforce documentation referenced

Frequently Asked Questions

Is Salesforce an ERP system?

No. The direct answer to is Salesforce an ERP system is that Salesforce is primarily CRM and platform software. It can integrate with ERP systems and store selected ERP-related records, but most orgs still use ERP for finance, inventory, procurement, fulfillment, and accounting controls.

What is Salesforce ERP integration?

Salesforce ERP integration connects Salesforce with an ERP system so users can share customer, product, quote, order, invoice, inventory, payment, or asset data. The integration can be real-time, scheduled, event-based, or live through external objects depending on the process.

Which ERP data should sync to Salesforce?

Sync only the ERP data that Salesforce users need to sell, support, or report. Common examples include customer number, product catalog, price list, inventory status, order status, invoice status, payment status, shipments, and assets. A Salesforce ERP design should define whether each record is editable in Salesforce or read-only from ERP.

Can Flow handle Salesforce ERP integration without Apex?

Flow can handle simple Salesforce ERP integration actions when the REST API call is clear and the error path is limited. Use Flow HTTP Callout for focused request-response work. Use Apex, middleware, Platform Events, or Change Data Capture when the process needs complex mapping, high volume, retries, or transaction recovery.

Should ERP inventory be copied into Salesforce?

Copy inventory into Salesforce only when users need reporting, automation, or offline access on that data. If users only need current availability during quote creation, a live API call or Salesforce Connect external object can be a better fit. The right Salesforce ERP pattern depends on freshness, volume, and what happens when the ERP is unavailable.

What limits affect Apex ERP callouts?

Apex ERP callouts must follow Salesforce governor limits. A single Apex transaction can make a maximum of 100 callouts, and tests must use callout mocks. Bulkify the code, avoid callouts inside loops, use Named Credentials for authentication, and move long-running work to Queueable Apex, Batch Apex, middleware, or events.