It arrives
An M3 order write is rejected, a closed period or a bad item number. Instead of a Confirm BOD that stops in silence, it enters the pipeline.
capturedIntegration · Makro Middleware
Your ERP stays the system of record. Shopify Plus becomes where the order gets placed.
The real problem
01 / backbone
Finance, warehouse inventory, agreement pricing, order management. The authoritative record the distribution, manufacturing or fashion business is run on.
02 / front door
Where B2B dealers and wholesale buyers place repeat orders without a phone call, a rep, or an EDI batch.
03 / the gap
Duplicate customers. Orders written twice. Pricing that drifts. Silent failures at month-end close.
Speaking M3's language: ION, BODs, API Gateway and the Event Hub
Products, images, attributes, pricing and availability are read out of Infor M3 and pushed to Shopify. The storefront never writes to the ledger. Orders, returns, shipments and fulfillment status are the only thing that travels both ways. M3 stays the system of record for catalog and stock; Shopify owns the order capture.
/M3/m3api-rest/execute. It fronts the surface and enforces governance.handshakeSyncItemMaster, customers, shipments via ProcessShipment / SyncShipment.M3 → MK.ionapi file; M3 never sees a password from our code.handshakeThe decision guide
Buyers have three paths: the official Infor eCommerce Connector (free, M3 CE, daily-bulk), a third-party iPaaS like Commercient SYNC, Alumio, Netgains or DCKAP, or a custom integration built on M3's ION / BOD layer and Shopify's Admin API. Each trades control and real-time accuracy against speed to stand up.
Infor's own free connector, BOD-based, targeting M3 CE. Basic B2C for standard products from stock, the buyer's default.
Right for a simple M3-CE B2C store on standard, in-stock items with no contract pricing.
Subscription middleware on a shared platform. Strong for standard managed sync across templated connectors.
Right for standard managed sync where the B2B logic fits a fixed-mapping template.
Built on M3's ION / BOD layer and Shopify's Admin API, around your exact order flow and agreement pricing. Owned by you, operated with a support agreement. Where M3 shops end up.
Right for Shopify Plus B2B contract pricing, configurable or style-SKU items, real-time multi-warehouse inventory, or a large industrial catalog that outgrows the basic connector.
The limits no vendor page admits
The free Infor eCommerce Connector is a starter integration for simple M3-CE stores. It handles the happy path and skips the failure modes that define real distribution, manufacturing and fashion catalogs. A custom middleware layer is built to handle every one of them, explicitly.
The standard connector is B2C and assumes paid-in-full at order entry. It does not sync customer data, so customer-group and contract-pricing-by-customer flows fall outside its reach entirely. No credit terms, no dealer accounts.
→ map each Shopify company to an M3 CUNOA flat price-list export misses the real price. M3 prices by search sequence: item base, price list, blanket agreement, promotion, discount model. Agreements and promotions outrank standard price lists, so the exported number is wrong at the second unit.
→ live-resolve OIS320MI.GetPriceLine at cartThe standard integration is explicitly normal items only: no styles and SKUs, no configurable, no attribute-controlled, no core items. A known gap for fashion and apparel and for distribution, where one Shopify product with variants can map to multiple M3 ITNOs.
→ load-bearing SKU ↔ ITNO join, mapped at sync timeInventory and pricing sync as daily bulk jobs, not continuously. Because Shopify commits at a specific warehouse location at checkout, a daily push on a high-velocity catalog is exactly where overselling happens between syncs.
→ event-driven via the Event Hub, per-warehouse availableThe connector carries only newly created Shopify orders and only at header level. Line-level detail, returns, multi-warehouse splits and the full order journey are not modeled. You cannot reconcile what you never captured.
→ full line-level orders, returns and shipments both waysION retries only connection-class failures. A business-logic rejection emits a Confirm BOD and stops, with no documented replay queue, dead-letter store or reconciliation. The connector's entire error story is a dashboard retry button. Basic tools fail silently.
→ dead-letter queue, per-order tracing, standing reconciliationClaims you can check
Every reality below is verified against a primary Infor source or a named vendor doc. This is the difference between a team that read the marketing and a team that shipped against the documentation.
1,000 req / 60s), a default request timeout of 1 minute, extendable to a max of 5, and a 10 MB buffered-payload cap. A naive per-order or per-product synchronous sync blows the throttle: design for batching, the Event Hub, and bulk reads from Data Lake.OIS275) via OIS100MI AddBatchHead → AddBatchLine → Confirm, and only earn a real order number (ORNO) after async validation. Build for eventual consistency and status-code handling. The real scaling ceiling is M3's batch-job queue (MNS300 Max active jobs), not an HTTP rate cap.CUOR / YREF, read before write, and hold the Shopify-order ↔ ORNO map yourself, because the final ORNO doesn't exist at submit time and a naive retry creates a duplicate order.WHLO); read the available figure M3 returns via MMS200MI/GetItmWhsBal, don't recompute it. Map M3 allocated → Shopify committed, M3 on-hand → Shopify on_hand, and let Shopify derive its own available. Locking the warehouse ↔ Shopify-location map is the number-one oversell prevention.OIS060) and promotions (OIS840) outrank standard price lists. Resolve, don't replicate: OIS320MI.GetPriceLine returns the fully resolved customer net price (NETP). Bulk-seed the catalog, then live-resolve the true B2B price at cart.CUNO) so agreements and promotions resolve, and M3 customer price lists map to Shopify Plus B2B catalog price lists with M3 as the single source of truth.OIS100MI GetHead / GetOrderValue behind "Include tax in MI") is a synchronous round-trip on a roughly 30-second-timeout path. Calculate cart tax in Shopify (native, or the same Avalara or Vertex engine M3 uses via CRS794) and let M3's invoice tax be the financial record.ITNO join is load-bearing, not product ↔ item. Mapping matrix and fashion items correctly is custom work, exactly the kind the basic connector skips.How we build it: architecture, monitoring, error handling, ownership
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 · ORNO not yet earned | PERMANENT · validation | 3 / 3 | held | Inspect |
| 07:55:22 | customer · CUNO-00910 | TRANSIENT · timeout | 2 / 5 | 09:50 | Retry now |
| 06:40:11 | item · ITNO-44120 | RATE_LIMIT | 1 / 5 | paced | Inspect |
Every record carries three identities at once: its M3 id, a canonical id, and its Shopify gid. The middleware reads this row before every write and decides create, update, or skip.
M3 has no native upsert and no automatic dedupe, so the platform owns identity. The Shopify-order to ORNO map is held here too, because the final order number doesn't exist at submit time. This is what stops duplicate customers 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.
CUOR / YREF stamped · ORNO held in key map
Inside the platform
Ten engineered subsystems, built on TypeScript and single-tenant. The same machine behind every adapter, the parts list your architect can verify.
01 / 10
When a record fails
ION retries only connection-class errors. A business-logic rejection emits a Confirm BOD and stops. The dead-letter and replay lane below is exactly the gap Makro owns. Color carries the verdict: amber is sorted, teal retries, red is held, green replays.
An M3 order write is rejected, a closed period or a bad item number. Instead of a Confirm BOD that stops in silence, it enters the pipeline.
capturedEvery failure is sorted before anything is retried, so a bad record never loops forever and never creates a duplicate order.
classifiedConnection-class and gateway-throttle failures retry with backoff and pacing, automatically, respecting the per-endpoint quota until they clear.
retryingA business-logic rejection routes straight to the dead-letter queue for review, with full context. It is never retried blindly or lost.
heldFix the cause, replay from the queue, idempotent on the held ORNO map. A daily reconciliation pass catches anything the live path missed.
replayed · reconciledHow long it takes
An Infor M3 ⇄ Shopify Plus build lands in one of three bands depending on B2B complexity, the number of warehouses and legal entities, and how many of the limits above are in play.
We price an Infor M3 integration as an engineering engagement: a build with a support agreement, not a per-record meter or a platform seat that renews forever. For market context, integration guides put a simple orders-and-inventory build at a few weeks and a complex multi-workflow build at several months, and enterprise iPaaS commonly runs into five and six figures a year. Your exact figure is scoped to the band and the limits in play, and we put it in writing before anything starts.
Security posture
The per-tenant .ionapi file and Shopify secrets are held as encrypted fields, isolated per tenant and rotatable without downtime. Nothing sits in plaintext, anywhere.
Every Shopify webhook is HMAC-verified before it is trusted, then deduplicated by event id, so a replayed webhook cannot create a second order.
HMAC · replay-safeOAuth 2.0 Resource Owner with a dedicated service account through the ION API Gateway, and at M3 a narrow MNS150 role with MNS090 API Security = 2, so unlisted transactions default to denied. The GRID-RunAsM3User role, never an admin login.
OAuth 2.0 · MNS090 = 2 · GRID-RunAsM3UserAn append-only audit trail logs every operation, source-tagged. Every M3 call is auditable (SES510) and revocable, so you can prove what happened during month-end close.
Frequently asked questions
The details that separate a team that read the docs from a team that shipped against them. Open any one.
m3api-rest, and use the Event Hub and ION BOD flows for change-driven sync. ION + API Gateway is the integration surface, not a direct REST resource model.OIS320MI.GetPriceLine, honoring blanket agreements and promotions that outrank standard price lists, and M3 customer price lists map to Shopify Plus B2B catalog price lists so dealer and wholesale accounts see correct contract pricing with M3 as the single source of truth. This is outside the free connector's scope because it does not sync customer data.The framework underneath
Every ERP sits behind the same contract: authenticate, fetch master data, push orders, validate, report. NetSuite runs in production today. Infor M3 is a registered target on that same framework, its path fully mapped to the ION API Gateway, MI programs, the Event Hub and ION BODs, with the M3 mechanics understood end to end.
We say this plainly: the credibility is a real platform and a precisely understood M3 path, proven by mapping a 12,000-SKU M3 catalog into Shopify metaobjects, not a decade of M3 production traffic. That distinction is exactly what your architect can verify, which is why we lead with it. The rest of the registry is an interface away.
Proof, outcomes, Shopify Plus Partner credibility
Lead with the one real Infor M3 proof, then the platform numbers your architect can verify on any adapter.
A real conversation about your M3 deployment, CE or on-prem, your data, and the three sharp questions you already have.