01 / backbone
SAP B1 is the ledger
Items, pricing, inventory, business partners, and orders. The authoritative record the business is run on.
Integration · Makro Middleware
SAP Business One ↔ Shopify Plus integration, built as custom middleware. Your ERP stays the system of record. Shopify Plus becomes where the order gets placed.
The real problem
Finance, inventory, pricing and order management on one side, B2B buyer self-serve on the other. The work is everything in the middle.
01 / backbone
Items, pricing, inventory, business partners, and orders. The authoritative record the business is run on.
02 / front door
Where B2B buyers place repeat orders without a phone call, a rep, or a re-keyed spreadsheet.
03 / the gap
Duplicate business partners. Orders written twice. Pricing that drifts. Silent failures at month-end close.
We built a product around that exact gap. SAP Business One plugs into it as a first-class, path-mapped adapter.
How the integration works (architecture)
Business partners, items, inventory and pricing are read out of SAP Business One and pushed to Shopify. The storefront never writes to the ledger. Orders are the only thing that travels both ways, and SAP Business One stays the source of truth.
System of record
read · never overwritten
The platform
map · reconcile · audit
The storefront
where buyers self-serve
/b1s/v2, REST/JSON over OData v4. The same Service Layer runs on both the HANA and SQL Server editions, so the middleware is written edition-agnostic. OData v3 was deprecated as of FP 2405.SAP B1 ⇄ MKge, not gt, because change timestamps are day-only precision.SAP B1 → MKB1SESSION and ROUTEID.handshakePATCH or POST, and pushed once into the document chain.Shopify ↕ SAP B1The console
Every sync, every failure, every reconciliation is visible. This is the same Makro Middleware console your team would watch in production. Move through the views.
| Time | Entity | Error class | Attempts | Next | Action |
|---|---|---|---|---|---|
| 08:13:04 | order · DocEntry 10288 | PERMANENT · −10 validation | 3 / 3 | held | Inspect |
| 07:55:22 | partner · CardCode C00910 | TRANSIENT · −5002 session | 2 / 5 | re-login | Retry now |
| 06:40:11 | item · ItemCode A-44120 | −2028 LOCKED | 1 / 5 | backoff | Inspect |
Every record carries three identities at once: its SAP B1 key, a canonical id, and the Shopify GID stamped into a dedicated U_ShopifyId UDF. The middleware reads this row before every write and decides create, update, or skip.
SAP B1 has no native upsert, so the platform owns it: GET-by-key, then branch PATCH versus POST. Sync a record twice and it updates. This is what stops duplicate business partners and double-posted orders before they reach your ledger.
Change detection runs on the stored checksum, so a catalog of 50,000 items with 12 real edits syncs 12 records, not 50,000.
entity key map · every id matched before write
Inside the platform
Ten engineered subsystems sit between SAP Business One and Shopify Plus. This is the machine, itemized. None of them is a setting you toggle, and each is something your team can watch run.
01 / 10
When a record fails
It is classified by SAP error code before it is retried, and nothing disappears into a log file. Colour carries the verdict: amber is sorted, teal retries, red is held, green replays.
A sales-order write to SAP Business One fails. Instead of disappearing into a log, it enters the pipeline with its full context.
capturedEvery failure is sorted by SAP error code before anything is retried, so a bad record never loops forever.
classifiedA −5002 session expiry re-logs in; a −2028 locked object backs off and retries, automatically, until it clears.
A −10 validation error routes straight to the dead-letter queue for review. It is never retried blindly or lost.
Fix the cause, replay from the queue. A daily reconciliation pass catches anything the live path missed.
replayed · reconciledThe ways to connect, and when each is right
SAP ships no first-party Shopify connector. Every working SAP B1 ⇄ Shopify integration is built a third way: a connector app, an iPaaS platform, or a custom build on SAP's Service Layer. The real decision is not native versus custom. It is which method fits your data, and who builds and owns the Shopify Plus storefront on top of it.
Where off-the-shelf connectors break
The two systems model data differently, and that is where naive connectors fail. These are the gaps we design around from day one, not the ones we discover in production.
App-store connectors push items to products and item groups to categories, one way. No inventory levels, no orders, no customers, no payments. A products-only one-way app is a non-starter for a real order-to-cash flow.
The Service Layer reports change dates with day-only precision. A record edited several times in a day is reported once, so a gt-timestamp poll silently misses intra-day edits and drifts. Robust sync uses ge plus a fuller scan or B1if events.
SAP B1 has no native upsert and POST is not idempotent. Re-posting a partner with an existing CardCode returns −10. A naive retry on a timed-out write that actually committed creates the duplicate sales order the iPaaS vendors warn about.
Auth is a cookie session that times out after 30 minutes idle and returns −5002 on expiry. A long fetch that does not pool and reuse the session, carrying both B1SESSION and ROUTEID, fails partway through.
SAP B1 has no stored available field. You publish OnHand minus IsCommited per warehouse, mapped to Shopify locations that rarely match SAP warehouse codes. Sync raw OnHand and you sell stock already promised to other orders.
SAP B1 is document-flow based and posted documents cannot be deleted. A connector that collapses a multi-line partial refund into a single credit memo silently mishandles the line detail and the order → delivery → invoice → return chain.
Claim vs reality
Every reality below is verified against a primary SAP or named-vendor source. This is SAP Business One, the SMB ERP, not SAP S/4HANA or ECC. That distinction is the first thing buyers get wrong.
CompanyService_GetItemPrice per partner, item and date, because the Service Layer cannot join tables.GetItemPrice resolves the base price list and special prices, and blanket agreements via its parameters. Whether it fully reflects discount groups and period/volume discounts must be verified on the live instance. If a gap exists, fall back to a saved query or layer the math in middleware. Do not assume full coverage.OnHand − IsCommited per warehouse, never raw OnHand, or you sell stock already promised. IsCommited is a soft allocation, and real-time reservation (Advanced ATP) exists only on the HANA edition. Stock moves on the Delivery, not the order.POST /Login returns a B1SESSION cookie (plus ROUTEID) mandatory on every request, timing out after 30 minutes idle. First login is ≈5 s, warm calls ≈20 ms, so you must pool and reuse the session, not authenticate per call.PATCH versus POST, use PATCH not PUT, and ETag/If-Match against concurrent edits.gt poll silently misses intra-day edits and drifts. Robust sync uses ge, pairs date-polling with a fuller scan or checksum, or taps B1if EventSender, because the Service Layer has no webhooks.U_<name>: no SAP-side endpoint, no API code change. The one catch: UDFs are absent from $metadata, so discover them per company DB via UserFieldsMD. UDTs surface as U_<table> for free.$apply aggregation is HANA, SQL Views are SQL. Confirm the edition and version.DELETE returns −5006). Order → DeliveryNotes (goods issue) → Invoices; refunds → Returns/CreditNotes, reversed with the Close/Cancel actions. A connector that collapses a multi-line partial refund into one credit memo silently mishandles the line detail and the chain.Security posture
Least-privilege access, verified inbound traffic, encrypted credentials, and a full audit trail. The questions your SAP consultant and your IT reviewer will ask, answered before they ask them.
The integration logs in as a dedicated Indirect Access user, never manager and never a Professional seat, with Full authorization only on the modules the sync touches and SAP B1's deny-by-default model for everything else. TLS 1.2/1.3, and a secure tunnel to on-prem.
Every Shopify webhook is HMAC-verified before it is trusted, then deduplicated by event id so a replay cannot create a second sales order.
HMAC · replay-safeSAP B1 and Shopify secrets are encrypted with AES-256-GCM, keys derived per context, isolated per tenant and rotatable without downtime. Zero credentials are stored in plaintext, ever.
AES-256-GCM · HKDF · per-tenantAn append-only audit trail logs every operation, source-tagged, so you can prove what happened during close.
append-only · source-taggedFrequently asked questions
The details that separate a team that read the docs from a team that shipped against them. Open any one.
The framework underneath
Every ERP sits behind the same contract: authenticate, fetch master data, push orders, validate, report. The platform runs in production today for NetSuite. SAP Business One has a fully mapped Service-Layer-first path against the same framework, against the real transports in this research: the Service Layer, DI API, B1if, and the B1SESSION cookie.
We say this plainly: NetSuite is the live production deployment. SAP Business One is path mapped, a precisely understood Service-Layer path, not a decade of B1 traffic. That distinction is exactly what your architect can verify, which is why we lead with it.
Proof, the replatforms we've run
Makro is a Shopify Plus partner. We have unified ERP, CRM and Shopify before: for Clarius we built a single account page over NetSuite ERP, Salesforce CRM and Shopify Plus, with Shopify Flow feeding orders into NetSuite. That is adjacent proof, NetSuite and Salesforce, not SAP Business One. The numbers below are the platform's checkable engineering standard, in production for NetSuite.
Automated tests across 139 suites, run on every change. No code reaches your production data without passing them. Counted in the repository, not rounded for the slide.
Coverage gate enforced before any deploy.
End-to-end browser tests across Chromium, Firefox, WebKit.
Failure classes, each with its own pre-decided policy.
Credentials stored in plaintext, anywhere, ever.
How long it takes and what it costs, honest bands
For market context: off-the-shelf connectors start around $99 per month, and packaged setups land in a roughly $15K–$40K range. That is the connector and iPaaS market anchor, not our quote. The point those numbers make is the one most buyers miss: the sync is rarely what the budget goes on. The Shopify Plus storefront and B2B experience build is.
Tier 1 · standard sync
Items, inventory and orders over a standard mapping, on an iPaaS or a connector app, with a modest Shopify Plus storefront. The right call when the data model is standard and the catalog is not exotic.
Tier 2 · custom B2B
A custom build on the Service Layer for merchants whose B2B catalog, customer-specific pricing, credit-limit enforcement or multi-warehouse stock has outgrown an off-the-shelf connector. The owned-platform option.
Tier 3 · headless / multi-store
One SAP B1 instance feeding multiple Shopify stores and Shopify Markets regions, routed by currency, warehouse and price list, with serialized or lot data and a headless or multi-region front-end.
Every Makro engagement is scoped per build and priced as an engineering engagement: a build with a support agreement, owned by you. No per-record meter, no platform seat. The market figures above are context for where connectors and iPaaS sit, not our number. We set yours from your actual SAP B1 environment, your catalog, and the B2B experience you need.
A real conversation about your SAP B1 environment, your edition and version, your price lists and warehouses, and the three sharp questions you already have.