Magento and SAP
Magento SAP integration
Price lists, special prices and stock per warehouse from SAP Business One into Magento, orders and business partners back. Built on the Service Layer and the Magento REST API, to your price lists and customer groups, then hosted and run for you. SAP S/4HANA is covered too.
What moves between Magento and SAP
Most Magento stores that connect to SAP run SAP Business One, the ERP for small and midsize companies. The integration reads and writes through the Service Layer, SAP's OData service for Business One. Six flows, each with a fixed direction and endpoint.
| Flow | Direction | Magento 2 REST | SAP Business One Service Layer |
|---|---|---|---|
| Items | to Magento | POST /V1/products |
Items |
| Prices | to Magento | POST /V1/products/tier-prices |
PriceLists, SpecialPrices |
| Stock | to Magento | POST /V1/inventory/source-items |
ItemWarehouseInfoCollection |
| Orders | to SAP | GET /V1/orders |
POST /Orders |
| Customers | to SAP | customer and order address | BusinessPartners |
| Shipments | to Magento | POST /V1/order/{id}/ship |
DeliveryNotes |
On SAP S/4HANA the same flows run through the sales order API, the material stock API and the pricing conditions; the differences are on the Shopify SAP integration page. The general setup is on e-commerce ERP integration.
Which system owns what
| Data | System of record | Direction | Sync behavior |
|---|---|---|---|
ItemCode, units, weight |
SAP | to Magento | changed items, by update date |
| Configurable parent, attribute set, images | Magento | stays in Magento | not written from SAP |
| Price lists | SAP | to Magento | nightly, as fixed prices |
| Special prices per business partner | SAP | to Magento | on change and on each period boundary |
| Stock per warehouse | SAP | to Magento, per source | changed quantities every few minutes |
| Orders | Magento until import, then SAP | to SAP | once, keyed on increment_id |
| Business partner and price list | SAP | Magento supplies new web customers | match on email, then create |
| Delivery and tracking | SAP or the WMS | to Magento | one shipment per delivery |
What Magento and SAP store differently
Special prices with a period, tier prices without one
SAP Business One prices an item from the business partner's price list. A special price for one business partner, item and price list overrides that. It can hold periods, with DateFrom and Dateto, and per period a quantity scale. Magento has two price tools, and neither matches. A tier price, with sku, customer_group, quantity, price and price_type, has a customer group but no date. A special price, with price_from and price_to, has dates but no customer group, and its start time must be later than the current time.
So the integration keeps the calendar. A special price valid from October 1 to December 31 is written as tier prices on October 1 and deleted with POST /V1/products/tier-prices-delete on January 1. It never uses PUT /V1/products/tier-prices for this: a PUT replaces all tier prices of a product, including those of every other customer group.
The sum. 40 business partners with special prices on 80 items each, with 2 quantity breaks, is 6,400 tier prices. Reading the 3,200 special prices from the Service Layer at 500 per page is 7 requests. Writing 6,400 tier prices to Magento takes 320 requests when input limits are on at 20 items per request, or 2 through the asynchronous bulk route at 5,000.
Price lists built on other price lists
A Business One price list can be derived: BasePriceList points to another list and Factor sets the ratio, followed by the list's own rounding method. Wholesale at factor 0.85 on a list price of 12.49 is 10.6165 before rounding. Magento's tier price of type discount applies a percentage without SAP's rounding. The integration writes every price as fixed, calculated in SAP, so a cent difference never reaches the invoice. More in money, tax and rounding.
Items without variants
The Items object in SAP Business One has no parent or variant property. Each size is its own item with an ItemCode of 20 characters in SAP's SDK reference. In Magento those items become simple products, and the configurable parent exists only in Magento: it has no ItemCode and never appears on an SAP order. Linking each child is one call, since POST /V1/configurable-products/{sku}/child takes one childSku. See variant mapping.
Warehouses and sources
Business One reports stock per warehouse as InStock, Committed and Ordered. Magento keeps quantity per source and subtracts its own reservations. Each SAP warehouse code, at most 8 characters, maps to one Magento source_code. Magento already holds back its own open orders, and SAP's Committed includes those orders once they are imported. The integration writes InStock minus only the quantity committed to orders from other channels, so a Magento order is not subtracted twice. See which stock counts.
Addresses and references
A Business One address has Street and Block of 100 characters each, City of 100, ZipCode of 20 and Country as a code of up to 3 characters. Magento's street array goes into Street and Block. The Magento increment_id goes into NumAtCard, the customer reference of 100 characters, and a new web customer gets a CardCode within its 15 characters. More in address field mapping.
The technical reality of this pair
| Limit | Magento 2 and Adobe Commerce | SAP Business One Service Layer |
|---|---|---|
| Requests | no general limit documented | no rate published, the server is the limit |
| Page size | all results when pageSize is missing |
20 by default, odata.maxpagesize per request |
| Batching | async bulk, 5,000 items per request | $batch with atomic change sets |
| Access | integration with OAuth 1.0a | login, B1SESSION cookie, 30-minute timeout |
| Order keys | entity_id, increment_id |
DocEntry, DocNum |
Checked on October 3, 2026 in Adobe's API security page and SAP's guide Working with SAP Business One Service Layer. Magento's input limits are off by default.
Neither side publishes a rate limit, and both are usually on servers that also serve people: the store's shoppers on one side, the users entering orders in SAP on the other. The integration runs heavy reads, such as the nightly price run, outside opening hours and keeps the order flow small and constant.
Bulk operations need a consumer. A bulk request returns a bulk_uuid and the work happens in Magento's message queue. If the consumer async.operations.all is not running, operations stay at status 4, open, without an error. The integration checks GET /V1/bulk/{uuid}/status after each batch.
SAP sessions expire. A Service Layer session ends after 30 minutes without use. The integration logs in again and resends the request. In a $batch, one failed request rolls back its whole change set, so each order goes in a change set of its own.
Where standard connectors stop
Standard connectors and iPaaS templates for Magento and SAP Business One map a price list to a customer group and a special price to a tier price. The period on a special price and the rounding of a derived price list are the two places where that mapping loses information, and a template that writes percentages or ignores dates shows a different price in the store than SAP puts on the invoice.
A built integration keeps the special price calendar, calculates fixed prices in SAP and follows your warehouse to source mapping. Comparison on technical grounds: custom integration vs iPaaS.
When it goes wrong
| What fails | What the integration does | What you see |
|---|---|---|
| Service Layer session expired | logs in again, resends | nothing |
| Business partner not found | order held, new partner proposed | the order and the email |
Order line with an unknown ItemCode |
that order held, the rest continue | the order and the SKU |
| Tier price delete missed at a period end | next price run removes it | a log line with the price |
| Bulk operation ends in status 3 | line goes to the checklist with its payload | the SKU and Magento's message |
| SAP down for maintenance | orders wait in the queue | the queue length |
An order that keeps failing is stored with its original payload and sent again once the cause is fixed. Every attempt uses the increment_id as its key, so a retry finds the existing SAP order instead of creating a second one. A reconciliation run compares recent Magento orders with NumAtCard values in SAP.
Before go-live the integration runs as a dry run against a test company database, writing nothing, and you approve the prices and orders it would write. After that every run has a diff per record. We host and monitor it and change it when Adobe or SAP changes an interface. The system side is on SAP Business One integration, the platform side on Magento integration, all flows on integrations. Sibling pages: Shopify SAP integration, Magento Business Central integration and Magento NetSuite integration. Tell us which SAP and which Magento you run.
Frequently asked questions
Does this work with SAP Business One and with S/4HANA?
Yes. SAP Business One runs through the Service Layer, on SAP HANA and, since 10.0 PL01, on SQL Server. S/4HANA runs through its OData APIs, such as API_SALES_ORDER_SRV for orders, where every order needs a sales organization, distribution channel and division. The Magento side is the same for both.
Can every business partner see their own prices in Magento?
Yes. Magento prices per customer group, so each business partner with special prices gets its own group, and its price list and special prices are written as tier prices for that group. On Adobe Commerce with B2B, a shared catalog can take the place of the group. See customer-specific pricing.
Why does a percentage discount give a different price in Magento than in SAP?
SAP Business One rounds a derived price list with its own rounding method. A Magento tier price of type discount applies the percentage without that rule. A price list at factor 0.85 on 12.49 gives 10.6165, which SAP may round to 10.60 and Magento shows as 10.62. We write fixed prices calculated in SAP, so both show the same amount.
Does it work with Magento Open Source?
Yes. Products, tier prices, sources, orders and shipments use the same REST API on Open Source and Adobe Commerce. Adobe I/O Events and webhooks need Adobe Commerce 2.4.4 or later; on Open Source the integration reads new orders by updated_at. Shared catalogs and company accounts exist only on Adobe Commerce with B2B.
Can we keep SAP Business One on SQL Server?
Yes. The Service Layer runs on SQL Server from SAP Business One 10.0 PL01. On older versions on SQL Server, the DI API is the remaining route: a COM library on a Windows machine that does not support multithreading, which limits how many orders and price updates run at the same time.
Tell us what you need
Tell us which systems you use and what needs to work better. We reply personally within one working day. We help you define the work, then agree the price and timing before you commit.
- You know the price and the timeline before you commit to anything
- We work out the connection that takes the work off your hands
- We handle the build, hosting, monitoring and maintenance
- Your team has less information to retype and fewer discrepancies to chase