
The ERP sync architecture is the single largest decision in an Adobe Commerce B2B implementation, and it is usually made too early, by the wrong people, and based on the wrong constraints. Real-time sync sounds modern and expensive. Batch sync sounds legacy and cheap. The truth is more interesting: most production distributors run a hybrid, the data type drives the sync pattern more than the platform does, and the wrong choice for a given data type causes problems that are hard to undo.
Bemeir’s Adobe Commerce B2B team has shipped ERP integrations with SAP S/4HANA, Microsoft Dynamics 365 Business Central, NetSuite, Oracle EBS, Epicor Kinetic, and Sage Intacct. The patterns repeat across all of them. Here is the framework we use when scoping the integration architecture before code starts.
What “sync” actually has to handle
The ERP integration in an Adobe Commerce B2B implementation has to manage seven distinct data flows. Each has its own latency tolerance and its own consequence-of-failure profile.
Customer master. Companies, accounts, users, addresses, contact information. Created and managed in the ERP, mirrored to Adobe Commerce.
Pricing. List prices, customer-group prices, customer-specific prices, tier prices, promotional pricing. The most complex data flow because the pricing logic in the ERP can be more sophisticated than what Adobe Commerce stores natively.
Inventory. Available-to-promise quantities, warehouse-specific stock, backorder rules. Critical for customer trust because a buyer placing an order on inventory that does not exist creates a fulfillment failure and a customer service incident.
Catalog. Products, attributes, categories, images, descriptions. Usually managed in a PIM or in the ERP, mirrored to Adobe Commerce.
Orders. Cart submissions become orders in Adobe Commerce, then need to flow to the ERP for fulfillment. This is the one flow that always goes from Adobe Commerce to ERP.
Credit and AR status. Credit limit, credit hold flag, open invoice balance, days past due. Used to gate checkout for accounts that are over their credit limit or on credit hold.
Order status updates. Shipment notifications, tracking numbers, invoice numbers. Flow from ERP back to Adobe Commerce so the customer can see order status in their account.
Each of these seven flows has different latency requirements. Forcing all of them into the same sync pattern is the most common architecture mistake we see in inherited implementations.
The latency tolerance for each data type
A useful way to think about real-time vs batch is to ask: what is the maximum acceptable lag between the ERP changing and Adobe Commerce reflecting that change, before a real business problem occurs?
| Data type | Acceptable lag | Sync pattern that fits |
|---|---|---|
| Customer master (new company) | Minutes to hours | Near real-time or hourly batch |
| Customer master (updated address) | Hours to one day | Daily batch is fine |
| Pricing (negotiated contract update) | One to four hours | Hourly batch or event-driven |
| Pricing (promotional price for the week) | One day | Daily batch is fine |
| Inventory (high-velocity SKUs) | Seconds to minutes | Real-time or sub-5-minute polling |
| Inventory (low-velocity SKUs) | Hourly | Hourly batch is fine |
| Catalog (new SKU or attribute change) | Hours | Hourly or daily batch |
| Orders (Magento to ERP) | Seconds | Real-time or near real-time |
| Credit and AR status | Seconds | Real-time or sub-5-minute polling |
| Order status (shipment notification) | Minutes to hours | Hourly batch typically fine |
The data tells you which patterns are required and which are nice-to-have. Inventory on high-velocity SKUs and credit status are the two that genuinely need real-time. Everything else has more latency tolerance than people realize.
Real-time sync: when it earns its cost
Real-time integration architectures are not free. They require event-driven infrastructure on both sides (the ERP needs to publish events when data changes, Adobe Commerce needs to consume those events and update its database), a message broker or queue (Kafka, RabbitMQ, Azure Service Bus, AWS EventBridge), idempotent handlers (so a duplicate event doesn’t corrupt data), and monitoring and replay capability (so a missed event can be reprocessed).
The cost is justified for three specific scenarios:
High-velocity inventory. When SKUs move through inventory faster than batch sync can catch, real-time is the only architecture that prevents overselling. Typical thresholds: SKUs that move more than one unit per minute during peak hours, or stores where a single overselling incident causes meaningful customer service cost.
Credit-sensitive accounts. When a substantial portion of order revenue comes from accounts that hit their credit limit during normal business operations, real-time credit checks at the checkout prevent orders from being placed against accounts that have just gone over limit.
Real-time pricing on volatile catalogs. Some distributors run pricing that changes during the day (commodities-linked pricing, FX-driven pricing, contract pricing that updates with raw material costs). For these, real-time price queries at the moment of catalog browse are the only way to show accurate prices.
For the median distributor we work with, these three scenarios are present but not for every SKU and every customer. The right architecture handles them where they are present and uses cheaper patterns where they are not.
Batch sync: when it is genuinely the right answer
Batch sync gets dismissed too easily as a legacy pattern. It is the right answer for a meaningful share of the data flows, and dismissing it costs money.
Daily batch for low-velocity data. Catalog metadata changes, customer address updates, low-volume SKU inventory, order status updates that aren’t time-critical. A 2am batch job that runs for 30 minutes can handle all of this and costs almost nothing to operate.
Hourly batch for pricing and product changes. Negotiated contract pricing updates that happen during business hours don’t need to be reflected within seconds, but should be reflected within an hour so that a buyer who knows their pricing changed today sees the new price when they browse.
Sub-five-minute polling for high-volume data. A polling pattern that runs every two to five minutes and pulls deltas from the ERP can handle most “near real-time” requirements without the infrastructure cost of event-driven architecture. The latency is acceptable for most use cases that aren’t truly real-time.
The trade-off batch makes is operational simplicity for latency. For most of the data flows in a B2B distributor implementation, that trade is worth making.
The hybrid pattern that works in production
The architecture our team consistently lands on for distributor implementations:
Real-time (event-driven): Inventory for high-velocity SKUs, credit limit and credit hold status, orders flowing from Adobe Commerce to ERP.
Sub-five-minute polling: Inventory for medium-velocity SKUs (anything that doesn’t qualify as high-velocity but matters for customer experience).
Hourly batch: Pricing updates (list price, customer group price, customer-specific price), new SKU additions, customer-specific catalog updates.
Daily batch: Customer master updates (new companies, address changes, user role changes), low-velocity SKU inventory, catalog metadata updates (descriptions, attributes, images), order status updates back to Adobe Commerce.
This pattern uses real-time infrastructure where it earns its keep and uses batch infrastructure where it is cheaper and adequate. The total infrastructure cost is roughly 40-60% of an all-real-time architecture, and the user experience is functionally indistinguishable.
The integration tooling that fits each pattern
The technical implementation depends on which sync pattern the data needs.
For real-time, event-driven flows: Adobe Commerce can subscribe to message queues (RabbitMQ is the native option, Kafka via custom integration is common at scale) and publish to them. The ERP side needs to publish change events; SAP S/4HANA does this well via the SAP Event Mesh, Microsoft Dynamics 365 Business Central via business events and webhooks, and NetSuite via SuiteScript triggers.
For polling integrations: A scheduled job (Magento cron, or a separate Node.js or .NET service) that calls the ERP’s REST or SOAP API for changed records since the last poll. Most ERPs support a “modified since” filter that makes delta polling efficient.
For batch integrations: Scheduled exports from the ERP (CSV, XML, or flat file) consumed by Adobe Commerce import jobs. This is the cheapest pattern to implement and operate, and is the right answer for the data flows that don’t need lower latency.
For middleware: A standalone service that sits between Adobe Commerce and the ERP, handling all sync flows in one place. This is often the cleanest architecture at scale because it isolates the integration logic from both the Magento codebase and the ERP customizations. Bemeir’s B2B team has built middleware in Node.js and in .NET for distributors who wanted this isolation.
Idempotency: the most missed requirement
Whatever sync pattern you choose, the handlers on the Adobe Commerce side need to be idempotent. The same event arriving twice (because of a retry, a network blip, or a reprocess) must not cause data corruption.
In practice this means: every sync operation should be expressed as “set this customer’s credit limit to $50,000” rather than “increment this customer’s credit limit by $5,000.” Set operations are idempotent. Increment operations are not, and the second arrival of the same event will overshoot.
The flows that most often miss this requirement are inventory updates (“reduce inventory by 5” instead of “set inventory to 47”) and pricing updates (“apply 10% discount” instead of “set price to $89.10”). When these flows are not idempotent, a missed acknowledgment causes data drift that is hard to detect and harder to fix retrospectively.
How to scope this in a discovery
When a distributor is scoping an Adobe Commerce B2B implementation with our team, the integration architecture conversation typically takes a full day of discovery. The structure that works:
First, list every data flow between the ERP and Adobe Commerce. The seven categories above are a starting point; add anything specific to the merchant’s business (custom dimensions, custom fields, custom workflows).
Second, define the latency tolerance for each flow honestly. Push back on the instinct to say “real-time” for everything; ask what business consequence occurs at one hour of lag, four hours of lag, one day of lag.
Third, map each flow to a sync pattern based on the latency tolerance.
Fourth, draw the integration architecture across both systems, naming the messaging infrastructure, the polling jobs, the batch exports, and the middleware (if any).
Fifth, scope the implementation effort per flow. The total integration effort is often 30-50% of the total Adobe Commerce B2B implementation effort. Treating it as a minor component is the surest way to blow the budget.
The merchants who get this right have integration architectures that scale with the business for years without major rework. The merchants who get it wrong are usually rebuilding the integration layer at month 18, after the first major scaling failure forces the issue. The architecture decisions made in week one are the decisions that determine which path the implementation takes.





