A Shopify order is not an ERP sales order. It becomes one only after something maps the customer, the lines, the tax, and the shipping into the objects your ERP will accept. Skipping that mapping is how teams end up with a warehouse that ships the Shopify SKU nobody recognises.
Start from a paid order, not from a cart
The useful event is the order being paid, or whatever status your finance team treats as committed. A webhook carries that event. The handler checks the signature before it trusts the body. Unsigned JSON is not an order.
Write the map before the code
Each Shopify line needs an ERP item, a unit, a tax behaviour, and a location. Discounts need a decision: a line discount, a header discount, or a price the ERP already knows. If a field has no home, the map says so. The alternative is a developer choosing at midnight during the first real order.
- Verify the webhook signature.
- Translate the order through the written map.
- Create the sales order once.
- Store the ERP id back against the Shopify order.
When the ERP does not answer
The event stays in a queue. A later retry uses the same idempotency key. If the first call actually succeeded and the response was lost, the retry finds the sales order instead of creating a twin. Someone should be able to see the failed reason without reading a server log on a laptop.
Stock is a separate decision
Creating the sales order does not decide who owns inventory. If the ERP owns it, Shopify should receive stock on a schedule, and the storefront should not be edited by hand to 'fix' a number the ERP will overwrite. Write that down in the same design. It is the argument you will otherwise have after the first oversell.
Questions
Which system should own inventory?
Usually the ERP or the warehouse, not Shopify. Shopify receives a stock number. It should not be a second place where stock is invented.
What stops a retry from creating two sales orders?
An idempotency key tied to the Shopify order, checked before the ERP create, so a replay finds the first success instead of inserting again.