Two systems that both believe they are right
A Salesforce–SAP integration is rarely hard because of connectivity; gateways and credentials get solved in the first week. The projects that go wrong fail on questions nobody wrote down: which system owns the customer, which engine computes the price, what happens when an order fails halfway, and who notices when the two sides disagree. SAP is the system of record for finance and logistics; Salesforce is where revenue is created. Both are, within their own domain, correct — the architecture's job is to make the boundary explicit.
This article walks the decisions that decide whether the integration survives production: master data ownership, the choice of SAP surface, order and invoice directions, the pricing source of truth, and the reconciliation machinery. For the general catalogue of styles these decisions draw on — request-reply, fire-and-forget, batch, event-driven — see our Salesforce integration patterns guide.
Master data ownership: customers and materials
The most consequential decision is who owns the customer master. In SAP, a customer is not one record: in ECC it is KNA1 plus sales-area views, in S/4HANA it is a Business Partner with roles, and in both worlds it fans out into partner functions — sold-to, ship-to, bill-to, payer — that finance and logistics depend on. Salesforce models the same reality as an Account with related records. A naive one-to-one mapping between Account and SAP customer collapses the first time one legal entity ships to forty plants under a single payer.
The pattern that works: Salesforce owns the record while it is a prospect — reps create freely, no ERP ceremony. At the first real order, the customer is created or extended in SAP, usually through a governed request rather than blind automation, and the SAP customer number is written back to Salesforce as the shared key. From that point on, trade-critical fields — payment terms, tax classification, credit data, partner functions — are SAP-owned and read-only in Salesforce, while relationship fields — ownership, segmentation, consent — stay Salesforce-owned. Ownership is a per-field contract, written down, not tribal memory. Skipping this step is how duplicate customers and blocked deliveries become weekly events.
Materials are simpler because the direction is one-way. SAP owns the material master; Salesforce needs a sales-relevant subset — number, description, sales unit, status, the attributes that drive selling — replicated into Product2, typically via MATMAS IDocs or an OData extraction. Do not drag plant, valuation or MRP views across; Salesforce has no use for them. The subtlety is the sales organisation and distribution channel dimension: a material sellable in one sales area and blocked in another has no natural home in a flat product catalog, so model that dimension explicitly rather than discovering it at order time.
IDoc, BAPI, OData — and where middleware sits
SAP exposes three main surfaces, and they are not interchangeable. Treat them as tools with different contracts and pick per interface, not per project.
IDocs: asynchronous and batched
IDocs are asynchronous documents moved over ALE — DEBMAS for customers, MATMAS for materials, ORDERS for orders, INVOIC for invoices. They are the workhorse of master data replication and document exchange: tolerant of downtime on either side, replayable, with decades of mature monitoring tooling on the SAP side. Their weakness is anything interactive — an IDoc will never tell a rep in real time whether an item is in stock.
BAPIs: synchronous, transactional, RFC
BAPIs are synchronous, transactional function calls — BAPI_SALESORDER_CREATEFROMDAT2 is still the canonical way to create an SD order programmatically. Two things matter. First, BAPIs speak RFC, not HTTP, so Salesforce cannot call them natively; something in the middle must do the protocol translation. Second, most write BAPIs do not commit on their own — the caller must issue BAPI_TRANSACTION_COMMIT, a detail that has produced more phantom "successful" orders than any other single mistake in this space.
OData: synchronous HTTP
S/4HANA's released OData APIs — and Gateway services on older stacks — are plain HTTP, which means Apex can call them directly through Named Credentials. They are the right surface for synchronous reads a user is actively waiting on: availability, credit status, a pricing simulation. Respect the constraints on both ends — CSRF token handling and throughput on the SAP side, callout limits and transaction time on the Salesforce side. Chatty, expand-heavy calls inside a rep's click path will not survive contact with production load.
Where does middleware sit in this? Our honest rule: direct point-to-point is defensible for a small number of synchronous reads. Anything involving orders, invoices or master data replication belongs behind an integration layer — MuleSoft, SAP Integration Suite, or equivalent — because you need protocol bridging for IDoc and RFC, guaranteed delivery, ordered retry, transformation in one testable place, and a single pane of glass for failures. Without it, the same logic ends up smeared across Apex triggers and ABAP user exits — the platform-boundary judgement we describe in when to write Apex — and when to walk away.
Orders and invoices: pick a direction and defend it
Every transactional document needs a declared direction, enforced ruthlessly. Orders flow from Salesforce to SAP, once, at a well-defined commit point — typically order activation, after quote approval. The payload must arrive SAP-ready: the SAP customer number resolved, SAP material numbers on every line, and a settled pricing decision (next section). SAP returns its order number, which you store on the Salesforce order immediately; that key pair is the backbone of every later status update, invoice link and reconciliation query. What you must not build is bidirectional order editing. Two systems updating the same order produces echo loops and duplicate updates; either amendments flow through the same Salesforce-to-SAP interface as the original order, or the order locks in Salesforce at submission and all change happens in SAP.
Everything after the order flows the other way. Delivery and billing statuses come from SAP — order confirmations, shipment notifications, change events — and land in read-only fields on the Salesforce order. Invoices are extracted from SAP, usually as INVOIC IDocs or an API pull, into a read-only replica object in Salesforce. That replica exists so sales, service and collections can see the financial reality of an account without an SAP login — not so anyone can edit it. The ERP remains the ledger, full stop. Where this traffic sits in the wider quote-to-cash picture is mapped in our order-to-cash reference architecture; when a commercial order must decompose into fulfilment steps before it reaches SAP, the patterns from our telco order orchestration article apply unchanged.
Pricing: decide the source of truth, then live with it
Both systems can price. SAP prices through the condition technique — decades of condition records, access sequences, rebate agreements and tax determination. Salesforce prices through price books, CPQ or Revenue Cloud pricing procedures. Running both at once is the classic failure: the quote says one number, the invoice says another, and every deal review becomes an investigation. Three patterns work in practice:
- SAP prices, Salesforce asks. The quote calls a synchronous sales order simulation and treats the returned net price as authoritative. Strongest when the pricing logic genuinely lives in SAP — heavy rebates, complex tax, plant-dependent costs. The costs are latency in the quoting path, tight runtime coupling, and simulation load on SAP that must be sized for your quote volume, not your order volume.
- Replicate SAP conditions into Salesforce. Condition records are extracted and mapped into price books or CPQ price rules. Honest assessment: this survives only for simple pricing. The condition technique does not translate faithfully into rule engines built on different assumptions, and the replica drifts within months. Treat it as a cache with a declared refresh contract, or do not do it at all.
- Salesforce prices, SAP records. CPQ or Revenue Cloud is the pricing master, and the order interface hands SAP the price as an external or manual condition that SD accepts as given. Cleanest for subscription and configured-product businesses where discounting already lives in the quote — the reality we describe in CPQ pricing in real-world deals. The catch is organisational: margin controls and pricing governance move to Salesforce, and finance must sign that off explicitly.
Whichever pattern you choose, the rule is the same: exactly one engine computes the net price the customer sees, and the other system consumes it. Hybrid pricing — SAP for some lines, Salesforce for others, on the same document — is where these projects go to die.
Error handling and reconciliation
Design for partial failure, because you will get it: SAP maintenance windows, locked master data, a material blocked in one sales area, a middleware redeploy mid-flight. The machinery that keeps this survivable:
- Idempotency at the write boundary. Order creation carries an external key — the Salesforce order identifier — checked on the SAP side before posting, so a retry after a timeout cannot create a duplicate order. Timeouts are not failures; they are unknown outcomes, and only idempotency makes retrying them safe.
- One correlation ID end to end. Generated at submission, stamped on the Salesforce record, the middleware message and the SAP document. When someone asks where an order went, the answer should be one search, not three.
- Transient and business errors on separate paths. Connectivity faults and lock contention retry automatically with backoff. Business errors — an inbound IDoc parked in error status, a failed credit check, a missing sales-area extension — must never retry silently; they route to a human work queue operations actually watches, and the failure surfaces on the Salesforce record so the rep is not selling against a phantom order.
- Reconcile on a schedule. A daily job compares both sides — orders created per day, invoice counts and totals per period — and alerts on drift, the same discipline we apply to payment data in bank-feed reconciliation on Salesforce. A reconciliation report nobody can argue with is what keeps both teams honest.
One uncomfortable truth about monitoring: half of it lives in SAP. Someone must own the IDoc queues and transactional RFC backlogs on that side, and the escalation path between the Salesforce team and the SAP basis team must exist before go-live — not be invented during the first incident.
Engineering notes from the field
Since 2010, Clouderia has built Salesforce–SAP integrations across automotive, telco, financial services, insurance and SaaS — 46 certified experts between Provo and Prague, with a strong preference for boring, observable architecture over clever synchronous coupling. The pattern that repeats: the interfaces are the easy part. Master data governance, a single pricing owner and reconciliation discipline are what decide whether the integration is trusted or worked around. If you are scoping one, our Salesforce integration services page describes how we run these projects end to end.
Frequently asked questions
Do we need middleware between Salesforce and SAP, or can we integrate directly?
Direct point-to-point is defensible for a small number of synchronous reads — an Apex callout to a released OData API for stock or credit checks. Anything involving orders, invoices or master data replication belongs behind middleware such as MuleSoft or SAP Integration Suite: you need protocol bridging for IDoc and RFC, guaranteed delivery, retry with idempotency, and one place to monitor failures. Point-to-point spreads that logic across Apex triggers and ABAP exits, where nobody can see it.
Which SAP interface should we use — IDoc, BAPI or OData?
Match the surface to the interaction. IDocs suit asynchronous, batched replication — master data, order confirmations, invoices — and tolerate downtime well. BAPIs give synchronous, transactional writes but speak RFC, which Salesforce cannot call natively. OData APIs are HTTP-based and fit synchronous lookups from Salesforce, such as availability or a pricing simulation. Most real architectures use two or three of them side by side, chosen per interface, not one for everything.
Should the customer master live in Salesforce or SAP?
Split it by lifecycle stage. Salesforce owns prospects and the relationship view; SAP owns the trade-critical customer master — payment terms, tax data, partner functions — from the first real order onward. The workable pattern: when a deal closes, the customer is created or extended in SAP, and the SAP customer number is written back to Salesforce as the shared key. Field-level ownership matters too: marketing attributes stay Salesforce-owned even on SAP-mastered customers.
Where should pricing live when both SAP and Salesforce can price?
Exactly one system should compute the net price a customer is quoted. Either SAP prices and Salesforce calls a pricing simulation for authoritative numbers, or Salesforce CPQ or Revenue Cloud is the pricing master and SAP accepts the price as an external condition. Replicating SAP condition records into Salesforce price logic looks attractive and drifts within months. The decision is organisational as much as technical — margin governance moves with the pricing engine.
How do we keep Salesforce and SAP from drifting apart?
Build reconciliation as a feature, not an afterthought. Carry one correlation identifier end to end, enforce idempotency on order creation so retries cannot duplicate documents, and route business errors to a human queue that operations actually watches. Then run a scheduled reconciliation that compares counts and amounts on both sides — orders per day, invoice totals per period — and alerts on drift. Silent divergence, not outages, is what erodes trust in the integration.
Related reading
Bring the hard part to a senior Salesforce engineering team.