Shopify Integration — Automation SOP

Owner: Operations Manager  |  Primary user: B2C Manager (Bridget Mokoena)  |  Store: jdz0br-kd.myshopify.com  |  Last reviewed: 8 August 2026

⚡ THE GOLDEN RULE

Shopify is the source of truth for the ORDER.
ERPNext is the source of truth for STOCK and the LEDGER.

Every Shopify order lands in ERPNext as a Sales Order. Stock only ever moves on the Delivery Note. The invoice is only submitted once the goods have physically left.

1. How Orders Are Received

Orders are pushed by Shopify, not polled on a timer. The chain is four steps and it is fully automatic:

#What happensWhere you can see it
1A shopper checks out. Shopify immediately fires an orders/create webhook.Shopify Admin → Settings → Notifications → Webhooks
2The webhook lands in ERPNext and is recorded as an Integration Request with service Shopify Webhook, status Queued.Integration Request list
3Velobiotics Shopify – Webhook Bridge reads that payload and arms a tight ±3 minute pull window on Shopify Setting. It creates no documents itself.Shopify Setting → Old Orders From / To
4The native job order.sync_old_orders runs, pulls that order over the Shopify Admin API and writes the Sales Order. Everything downstream follows from there.Ecommerce Integration Log
Why the bridge exists. The webhook is delivered to the old endpoint left behind by the retired shadow service. We kept that doorway because Shopify reliably knocks on it, but the shadow writer itself is blocked. The bridge turns the knock into a signal; the native app still does 100% of the writing. That way there is exactly one thing creating orders, customers and invoices.
If an order sits in ERPNext unimported, check the Integration Request list first. A row stuck on Queued means the bridge did not fire. A row that never appeared at all means Shopify did not deliver — check the webhook is still registered in Shopify Admin.

2. Frequency — What Runs When

Normal end-to-end latency from checkout to a Sales Order in ERPNext is under 5 minutes.

TriggerFrequencyWhat it does
Shopify orders/create webhookInstant, on checkoutRecords the Integration Request
Velobiotics Shopify – Webhook BridgeInstant, on that recordArms the pull window
order.sync_old_orders (native)Every 5 minutesPulls the order, creates the Sales Order. Idles instantly when nothing is armed.
Velobiotics Shopify – Route OrderInstant, on Sales Order submitDraft Sales Invoice + draft Pick List + Bridget's call task
Velobiotics Shopify – Hourly Catch-up ArmEvery hour at :50Safety net. Re-scans the last 4 hours so a missed webhook cannot lose an order.
Velobiotics B2C – Daily Shopify Call Tasks07:00 dailyRaises the abandoned-cart call task only
Inventory push to ShopifyStoppedDeliberately off — stock is not pushed back to Shopify
Rule of thumb: checkout → Sales Order ≤ 5 min → Bridget's call task the same second → worst case the hourly net catches it by :50.

3. The Order Flow — End to End

Shopify order placed | v [1] Sales Order created and submitted automatically (status = Shopify financial status) | +--- PAID -------> [2] Draft Sales Invoice (Update Stock = OFF, Invoice Source = Shopify) | | | +--> [3] Draft Pick List (Finished Goods - V) | | | +--> [4] Tax invoice PDF emailed to the warehouse printer | | | v | [5] Warehouse picks and packs -> submits Pick List | | | v | [6] Delivery Note created and submitted <-- STOCK MOVES HERE | | | v | [7] Sales Invoice submitted automatically; order marked fulfilled | +--- NOT PAID ---> [2b] Task created for B2C (Bridget) to call and collect payment No invoice is raised until Shopify reports the order as paid.

What each step guarantees

StepDocumentRule that is enforced automatically
1Sales OrderSubmitted. Carries Shopify order ID, order number and payment status.
2Sales InvoiceStays in Draft. Update Stock = 0. Invoice Source = Shopify. Order Date = the Shopify order date, not today.
3Pick ListWarehouse forced to Finished Goods - V and linked back to its invoice.
6Delivery NoteThe only document that moves stock.
7Sales InvoiceSubmitted on Delivery Note submit. Shopify order status set to fulfilled.

4. Money — Where the Numbers Land

ItemAccountRule
VAT200300 Standard Rate VAT 15%Always
Shipping charged by Shopify100100 Shipping Revenue - VRevenue, never an expense account
Free shipping (orders over R500)100100Posts as zero — the line still appears
Do not round. Rounded Total is switched off on all Shopify invoices. An order of R1 274.80 must read R1 274.80 in ERPNext, not R1 275. The exact cents are how we match an ERPNext invoice back to a Shopify order and to the payment gateway settlement.

5. Customers — One Human, One Record

Before the sync creates a customer it searches for an existing one, in this order:

TierMatch onNotes
1EmailCustomer email field and any linked Contact email
2PhoneLast 9 digits, so +27 / 0 prefixes do not matter
3Exact nameOnly if there is exactly one match and that record has no conflicting email or phone

When a match is found the Shopify customer ID is written onto the existing record and it is reused. A duplicate is only created when all three tiers come back empty.

A customer name ending in “ - 1” is a duplicate created before this rule existed. These are being merged manually. Never create one deliberately.

6. Items — SKU Is the Only Key

Shopify variants map to ERPNext items strictly by SKU, held in the Ecommerce Item table. Never create a new ERPNext item to satisfy a Shopify order — find the existing SKU and map it.

  • If an order line arrives with a blank Item Code, the SKU has no mapping. Add the mapping, then re-sync the order.
  • Bundles: where Shopify sells a bundle, the individual component SKUs are the source of truth for stock. The bundle is a Product Bundle in ERPNext and explodes into its components on the Delivery Note.
  • An item code that looks like a long number (e.g. 44605740253355) is a Shopify variant ID that leaked in as a placeholder. That is a fault — report it.

7. B2C Call Tasks (Bridget)

Call tasks are raised with the order, not on a batch. A customer called minutes after checking out converts far better than one called the next morning, so the task is created in the same transaction that creates the Sales Order.

SituationWhen the task appearsTask subjectWhat Bridget does
New paid orderImmediately on importShopify NEW order #SPF… – call customer to confirm order and advise fulfilmentCall to confirm the order, verify the delivery address, advise fulfilment timing
Pending paymentImmediately on importShopify UNPAID order #SPF… – call customer for paymentCall and request payment, then update the order
Abandoned cart07:00 each working dayShopify abandoned carts <date> – call shoppers and offer a recovery discountWork the Shopify abandoned-checkout list, find out what stopped them, offer the approved discount

Every task is High priority, starts today, and carries a ToDo assigned to support@velobiotics.com so it shows on Bridget's own list.

One order, one call

An order gets either the confirmation task or the payment task — never both. This is deliberate: it stops the same customer being phoned twice about the same order.

Working days — how the deadline is chosen

The deadline is the same day wherever possible. If today is not a working day for Bridget, the deadline rolls forward to her next working day. Two things are checked, in order:

  • Company holiday list (currently South Africa 2026) — this already contains every Saturday and Sunday as well as public holidays.
  • Approved leave — any submitted, approved Leave Application covering that date.
Worked example. Orders #SPF11429 and #SPF11431 imported on Saturday 8 August 2026. Saturday and Sunday are non-working, and Monday 10 August is National Women's Day (observed). Both tasks were therefore dated Tuesday 11 August 2026 automatically.
The abandoned-cart job simply skips non-working days rather than rolling forward — the next working day's 07:00 run raises a fresh task. Abandoned checkouts are not synced into ERPNext; that list lives in Shopify Admin only.

8. Automation Status

ComponentTypeScheduleState
Velobiotics Shopify – Webhook BridgeIntegration Request, After InsertInstantON
order.sync_old_ordersNative scheduled jobCron */5 * * * *ON
Velobiotics Shopify – Route OrderSales Order, After SubmitInstantON
Velobiotics Shopify – Match Existing CustomerEcommerce Integration Log, Before SaveInstantON
Velobiotics Shopify – DN Submit Closes InvoiceDelivery Note, On SubmitInstantON
Velobiotics Shopify – Print Paid InvoiceSales Invoice eventInstantON
Velobiotics Shopify – Hourly Catch-up ArmScheduler eventCron 50 * * * *ON
Velobiotics B2C – Daily Shopify Call TasksScheduler eventCron 0 7 * * *ON
Shadow Block – Customer / Sales Order / Sales InvoiceBefore Insert guardsAlwaysON
Inventory push to ShopifyNative scheduled jobSTOPPED (intentional)
erpnext_shopify appLegacy appNOT INSTALLED
Known noise. The Error Log shows App erpnext_shopify is not installed roughly every 30 minutes. That is a stale webhook subscription still registered in Shopify pointing at the removed app; Shopify keeps retrying it. It is harmless but should be deleted in Shopify Admin → Settings → Notifications → Webhooks.

9. Troubleshooting

SymptomCauseFix
Order in Shopify but not in ERPNextWebhook not deliveredWait for the hourly catch-up, or ask Operations to run the sync for that time window
Invoice line has a blank Item CodeSKU has no Ecommerce Item mappingAdd the mapping, then re-sync the order
Invoice Source shows blankStale browser cacheHard refresh with Ctrl+Shift+R
Customer created ending in " - 1"No email, phone or name match foundMerge into the original and report it
Sales Invoice owned by "Guest"Legacy shadow serviceReport immediately — this should be impossible
Stock does not reconcile on FridayAn invoice was submitted with Update Stock ONReport to Operations; stock must only move on the Delivery Note

10. Never Do This

  • Never tick Update Stock on a Shopify Sales Invoice.
  • Never submit a Shopify invoice before the goods have shipped — the Delivery Note does it for you.
  • Never create a new Item to satisfy a Shopify order. Map the SKU instead.
  • Never change the warehouse away from Finished Goods - V.
  • Never re-enable the old Shopify service or the fix_shopify_* scripts.
  • Never round a Shopify total.

Questions or a fault to report: Operations Manager.