Branch8

香港零售品牌 Shopify Plus 多倉庫庫存同步實戰教學:本地倉 + 英國倉

Matt Li
September 28, 2026
13 mins read
香港零售品牌 Shopify Plus 多倉庫庫存同步實戰教學:本地倉 + 英國倉

Key Takeaways

  • 用 `inventorySetQuantities` 送絕對值,配 `compareQuantity` 避免覆蓋衝突
  • 每個倉一個 Location,一個 Shipping Profile,嚴禁雙向權威來源
  • 英國 £135、歐盟 €150 稅務門檻決定從哪個倉出貨
  • Webhook 必須驗 HMAC、依 webhook-id 去重、防止同步迴圈
  • 先用香港直寄累積流速數據,再決定前置哪些 SKU 到英國倉

要在 Shopify Plus 同步香港本地倉與英國倉,核心是四件事:為每個倉建立獨立 Location、用 Shopify Markets 與 Shipping Profile 界定服務範圍、以 GraphQL Admin API 的 inventorySetQuantities 做單向權威同步、再以 inventory_levels/update webhook 回寫 WMS。以下是完整設定流程。

為什麼香港品牌需要「本地倉 + 英國倉」雙倉架構?

香港零售品牌出海英國與歐盟時,最常見的兩難是:全部從香港直寄,運費與清關時間吃掉轉換率;全部備貨到英國,又會把現金壓在海外庫存上。雙倉架構是折衷解——高流速 SKU 前置到英國倉做 2–3 日到貨,長尾 SKU 留在香港倉直寄。

這個架構之所以在 2026 年更值得做,是因為稅務邊界已經固定下來。根據英國 HMRC 的跨境貨物增值稅指引,貨值 £135 以下、由境外直寄英國消費者的商品,賣方須自行註冊英國 VAT 並在銷售時收取稅款;超過 £135 則按進口處理。歐盟方面,根據歐盟委員會稅務與關務總署(DG TAXUD)的 IOSS 制度,€150 以下的進口遠距銷售可透過 IOSS 一站式申報。換句話說,商品從哪個倉出貨,直接決定了稅務路徑與買家的到手價,庫存同步錯誤不只是缺貨問題,而是報稅問題。

技術上,Shopify Plus 本身足以承載這個架構。根據 Shopify Help Center 的 Locations 文件,Shopify Plus 方案最多可設定 1,000 個庫存地點,遠高於基本方案的 10 個,足以涵蓋香港自營倉、英國 3PL、門市與寄售點。

開始前需要準備什麼?

帳號與權限

  1. Shopify Plus 商店,具備 Store owner 或含 write_inventory、write_locations、write_fulfillments 權限的 staff 帳號。
  2. 一個 Custom App(Admin → Settings → Apps and sales channels → Develop apps),取得 Admin API access token(shpat_...)。
  3. Admin API 版本建議使用 2025-10 或更新版本;inventorySetQuantities 在 2024-04 之後為正式的庫存設定入口。

系統與資料

  • 香港倉的 WMS 或 ERP(常見為 SAP Business One、NetSuite、Odoo 17,或自建系統)能輸出以 SKU 為 key 的可售量。
  • 英國 3PL 提供 API 或至少每小時一次的 CSV / SFTP 庫存檔。
  • 一份乾淨的 SKU 主檔:同一件商品在兩地必須用同一組 SKU。這一步沒做好,後面所有同步都會變成人工對帳。

環境檢查指令

1export SHOP="your-store.myshopify.com"
2export TOKEN="shpat_xxxxxxxxxxxxxxxx"
3export API="2025-10"
4
5curl -s -X POST "https://$SHOP/admin/api/$API/graphql.json" \
6 -H "X-Shopify-Access-Token: $TOKEN" \
7 -H "Content-Type: application/json" \
8 -d '{"query":"{ shop { name plan { displayName } } locations(first: 10) { edges { node { id name isActive } } } }"}' | jq

預期輸出應包含 "displayName": "Shopify Plus" 以及現有 location 清單。若回傳 403,代表 token scope 未包含 read_locations。

Ready to Transform Your Ecommerce Operations?

Branch8 specializes in ecommerce platform implementation and AI-powered automation solutions. Contact us today to discuss your ecommerce automation strategy.

步驟一:規劃倉庫拓撲與命名規則

在按任何按鈕之前,先把拓撲寫下來。我們在協助一家大中華區服飾零售集團規劃跨境倉時,最耗時的不是 API,而是釐清「哪一個 location 對哪一個市場、由誰負責更新」。

建議的命名規則採用 國別代碼-倉型-序號:

  • HK-DC-01 — 香港自營中央倉,出貨至香港、澳門、台灣、東南亞,以及英國 £135 以下直寄訂單。
  • GB-3PL-01 — 英國第三方倉(多在 Midlands 一帶),出貨至英國本島與歐盟。
  • HK-RETAIL-xx — 門市庫存,僅供 BOPIS 與門市履約,預設不對線上訂單開放。

同時決定每個 location 的「權威來源」:香港倉由 ERP 為準,英國倉由 3PL 為準,Shopify 永遠是下游。雙向權威(兩邊都能改)是多倉同步事故的頭號成因,除非你已有具備 conflict resolution 的中介層,否則不要嘗試。

步驟二:建立 Location 並啟用庫存追蹤

可在後台手動新增,但用 API 建立比較容易納入版本控管:

1mutation CreateUkLocation($input: LocationAddInput!) {
2 locationAdd(input: $input) {
3 location { id name address { countryCode } }
4 userErrors { field message }
5 }
6}

Variables:

1{
2 "input": {
3 "name": "GB-3PL-01",
4 "address": {
5 "address1": "Unit 4, Trident Park",
6 "city": "Nuneaton",
7 "countryCode": "GB",
8 "zip": "CV11 6RY"
9 },
10 "fulfillsOnlineOrders": true
11 }
12}

成功後會回傳 gid://shopify/Location/1234567890。把兩個 location GID 記到環境變數:

1export LOC_HK="gid://shopify/Location/1111111111"
2export LOC_GB="gid://shopify/Location/2222222222"

接著把商品在兩個 location 都設為 stocked。若 SKU 數量多,用 bulk operation 比逐筆 activate 快得多:

1mutation ActivateItem($inventoryItemId: ID!, $locationId: ID!) {
2 inventoryActivate(inventoryItemId: $inventoryItemId, locationId: $locationId) {
3 inventoryLevel { id quantities(names: ["available"]) { name quantity } }
4 userErrors { field message }
5 }
6}

注意:只在該倉真的會備貨的 SKU 上啟用。把全部 SKU 在兩地都 activate,會讓 Shopify 的訂單路由把「0 件但已啟用」的倉視為候選地點,造成不必要的分單。

Ready to Transform Your Ecommerce Operations?

Branch8 specializes in ecommerce platform implementation and AI-powered automation solutions. Contact us today to discuss your ecommerce automation strategy.

步驟三:用 Shopify Markets 與 Shipping Profile 劃分服務範圍

Location 決定「貨在哪」,Shipping Profile 決定「哪個倉能寄到哪」。這兩者若不對齊,會出現英國客人被指派香港倉、卻顯示英國本地運費的情況。

設定順序:

  1. Settings → Markets:建立 United Kingdom、European Union、Hong Kong & Greater China、Rest of APAC 四個市場,各自設定貨幣(GBP / EUR / HKD / USD)與稅務。英國市場需填入英國 VAT 註冊號,歐盟市場填 IOSS 號碼。
  2. Settings → Shipping and delivery → Custom profile:建立「UK Domestic」profile,只掛 GB-3PL-01,zone 設 United Kingdom,費率如 Standard £3.95 / Free over £50。
  3. 再建立「Cross-border from HK」profile,只掛 HK-DC-01,zone 涵蓋 UK、EU、APAC,費率反映實際空運成本。
  4. General profile 保留香港本地與門市自取。

根據 Shopify 的 Shipping profiles 文件,當訂單中的商品分屬不同 profile,Shopify 會分別計算並疊加運費——這正是你要避免的體驗。實務做法是:在英國倉備齊「常一起購買」的組合 SKU,把混倉訂單的比例壓低,而不是靠前台隱藏費率。

步驟四:從 ERP/WMS 推送庫存到 Shopify

使用 inventorySetQuantities 做絕對量同步

inventoryAdjustQuantities 是增量調整(delta),inventorySetQuantities 是設定絕對值。跨系統同步一律用絕對值——增量在重試時會重複計算,絕對值天然冪等。

1mutation SetStock($input: InventorySetQuantitiesInput!) {
2 inventorySetQuantities(input: $input) {
3 inventoryAdjustmentGroup {
4 createdAt
5 reason
6 changes { name delta quantityAfterChange }
7 }
8 userErrors { field code message }
9 }
10}

Variables(一次送兩個倉):

1{
2 "input": {
3 "name": "available",
4 "reason": "correction",
5 "ignoreCompareQuantity": false,
6 "quantities": [
7 {
8 "inventoryItemId": "gid://shopify/InventoryItem/44556677",
9 "locationId": "gid://shopify/Location/1111111111",
10 "quantity": 128,
11 "compareQuantity": 130
12 },
13 {
14 "inventoryItemId": "gid://shopify/InventoryItem/44556677",
15 "locationId": "gid://shopify/Location/2222222222",
16 "quantity": 42,
17 "compareQuantity": 45
18 }
19 ]
20 }
21}

compareQuantity 是樂觀鎖:如果 Shopify 當前值與你以為的不同(例如期間有訂單扣減),mutation 會回傳 userErrors 而非盲目覆蓋。生產環境請務必帶上,並把錯誤送進重新讀取後重試的佇列。

批次與速率控制

Admin GraphQL API 採用 cost-based 的 leaky bucket 限流。根據 Shopify 開發者文件,Shopify Plus 的 API 額度為標準方案的 10 倍,但你仍應在每次回應中讀取 extensions.cost.throttleStatus.currentlyAvailable 來自我節流:

1// sync-inventory.js — Node 20, 無額外依賴
2const SHOP = process.env.SHOP;
3const TOKEN = process.env.TOKEN;
4const API = process.env.API || "2025-10";
5
6async function gql(query, variables) {
7 const res = await fetch(`https://${SHOP}/admin/api/${API}/graphql.json`, {
8 method: "POST",
9 headers: {
10 "X-Shopify-Access-Token": TOKEN,
11 "Content-Type": "application/json"
12 },
13 body: JSON.stringify({ query, variables })
14 });
15 const json = await res.json();
16 const cost = json.extensions?.cost?.throttleStatus;
17 if (cost && cost.currentlyAvailable < 200) {
18 await new Promise(r => setTimeout(r, 1500)); // 讓桶回填
19 }
20 if (json.errors) throw new Error(JSON.stringify(json.errors));
21 return json.data;
22}
23
24// 每批最多 250 筆 quantities,超過請切片
25export async function pushBatch(quantities) {
26 const chunks = [];
27 for (let i = 0; i < quantities.length; i += 250) {
28 chunks.push(quantities.slice(i, i + 250));
29 }
30 for (const chunk of chunks) {
31 const data = await gql(SET_STOCK_MUTATION, {
32 input: { name: "available", reason: "correction", quantities: chunk }
33 });
34 const errs = data.inventorySetQuantities.userErrors;
35 if (errs.length) console.error("部分失敗:", errs);
36 }
37}

同步頻率建議:香港倉(自營、變動頻繁)每 5–10 分鐘增量推送;英國 3PL(檔案交換為主)每小時全量對帳一次,並在每日香港時間凌晨 3 點(英國前一日晚間 7 點,兩地都非出貨尖峰)跑一次完整核對。

Ready to Transform Your Ecommerce Operations?

Branch8 specializes in ecommerce platform implementation and AI-powered automation solutions. Contact us today to discuss your ecommerce automation strategy.

步驟五:設定 Webhook 讓 Shopify 回寫下游系統

訂單在 Shopify 扣庫存後,WMS 必須知道。訂閱 inventory_levels/update 與 orders/fulfilled:

1curl -s -X POST "https://$SHOP/admin/api/$API/graphql.json" \
2 -H "X-Shopify-Access-Token: $TOKEN" \
3 -H "Content-Type: application/json" \
4 -d '{
5 "query": "mutation Sub($topic: WebhookSubscriptionTopic!, $sub: WebhookSubscriptionInput!) { webhookSubscriptionCreate(topic: $topic, webhookSubscription: $sub) { webhookSubscription { id } userErrors { message } } }",
6 "variables": {
7 "topic": "INVENTORY_LEVELS_UPDATE",
8 "sub": { "callbackUrl": "https://ops.example.com/hooks/shopify/inventory", "format": "JSON" }
9 }
10 }' | jq

接收端必須驗證 HMAC,否則任何人都能偽造庫存事件:

1import crypto from "node:crypto";
2
3function verify(rawBody, hmacHeader, secret) {
4 const digest = crypto.createHmac("sha256", secret)
5 .update(rawBody, "utf8").digest("base64");
6 return crypto.timingSafeEqual(Buffer.from(digest), Buffer.from(hmacHeader));
7}

並記得處理迴圈:由 Shopify webhook 觸發的 WMS 更新,不應再推回 Shopify。做法是在中介層對每個 inventory_item_id + location_id 記錄最後一次由自己推送的值與時間戳,若 webhook 回傳的值與之相符,直接丟棄。

步驟六:用 Shopify Flow 處理路由與異常

Shopify Flow 隨 Plus 方案提供,適合做不需要寫 code 的營運規則。三個高價值的 workflow:

缺貨自動切換履約倉

  • Trigger:Inventory quantity changed
  • Condition:Location = GB-3PL-01 且 available <= 0 且 SKU 在 HK-DC-01 有貨
  • Action:加上 tag ship-from-hk,並發 Slack 通知補貨負責人

前台可用該 tag 在商品頁顯示「此款由香港直寄,預計 5–8 個工作天」,讓交期預期在下單前就對齊。

混倉訂單標記

  • Trigger:Order created
  • Condition:訂單商品同時需要兩個 location
  • Action:加 tag split-shipment,交客服主動通知分批到貨

高價值跨境訂單稅務檢查

  • Trigger:Order created,shippingAddress.countryCode = GB
  • Condition:subtotal > £135 且 fulfillment location = HK-DC-01
  • Action:加 tag duty-on-import,由報關流程接手,避免客人到貨才被 courier 收費

Ready to Transform Your Ecommerce Operations?

Branch8 specializes in ecommerce platform implementation and AI-powered automation solutions. Contact us today to discuss your ecommerce automation strategy.

步驟七:設定訂單路由優先順序

在 Settings → Shipping and delivery → Order routing 中,把優先順序設為:

  1. Closest location —— 讓英國訂單優先落在 GB-3PL-01
  2. Fewest locations(minimise split) —— 減少分單
  3. 手動排序作為 tiebreaker:GB-3PL-01 → HK-DC-01 → 門市

門市 location 應關閉 fulfillsOnlineOrders,除非你真的要做 ship-from-store。香港門市面積小、人手緊,把線上單塞進門市通常換來的是漏單而非更快到貨。

步驟八:驗收清單與測試腳本

上線前逐項打勾:

  1. 建立一個 £5 測試商品,兩倉各 3 件。從英國地址下單,確認扣的是 GB-3PL-01。
  2. 把 GB 倉設為 0,重下單,確認自動落到 HK-DC-01 並顯示跨境運費。
  3. 下一張混倉訂單,確認 Shopify 產生兩張 fulfillment order。
  4. 在 ERP 側改一個 SKU 數量,10 分鐘內確認 Shopify 反映(含 compareQuantity 未觸發錯誤)。
  5. 取消一張已付款未出貨的訂單,確認庫存回補到正確 location。
  6. 用 compareQuantity 故意送錯值,確認你的重試邏輯會 re-read 而非硬覆蓋。

快速核對兩倉數量的查詢:

1query CheckSku($sku: String!) {
2 productVariants(first: 1, query: $sku) {
3 edges { node {
4 sku
5 inventoryItem {
6 inventoryLevels(first: 10) {
7 edges { node {
8 location { name }
9 quantities(names: ["available", "committed", "incoming"]) { name quantity }
10 } }
11 }
12 }
13 } }
14 }
15}

Ready to Transform Your Ecommerce Operations?

Branch8 specializes in ecommerce platform implementation and AI-powered automation solutions. Contact us today to discuss your ecommerce automation strategy.

常見問題排除

庫存數字對不上,差額固定等於未出貨訂單量

你同步的是 available,但 ERP 給的是「實物庫存」。Shopify 的 available 已扣除 committed(已下單未出貨)。解法:ERP 端推送 實物 − 保留量,或改為同步 on_hand 並讓 Shopify 自行計算 committed。

userErrors 出現 INVENTORY_LEVEL_NOT_FOUND

該 SKU 在目標 location 尚未 activate。先呼叫 inventoryActivate,再重試 set。建議在同步器中對此錯誤碼做自動 activate + retry。

英國客人看到香港運費

Shipping profile 與 location 綁定錯誤,或商品同時掛在兩個 profile。到 Shipping and delivery 檢查該商品出現在哪些 profile;一個商品可以在多個 profile 中,但每個 profile 只應對應其倉的費率。

Webhook 收不到或重複

Shopify 的 webhook 為 at-least-once 投遞,重複是正常的。接收端必須依 X-Shopify-Webhook-Id 去重,並在 5 秒內回 200;重活丟給背景佇列。根據 Shopify 開發者文件,連續投遞失敗達一定次數後訂閱會被移除,因此要監控 webhook 健康度。

429 Throttled 大量出現

檢查是否在 for-loop 中逐筆呼叫。把 250 筆合併成一次 inventorySetQuantities,成本遠低於 250 次單筆呼叫。大規模初始化改用 Bulk Operations API。

跨境營運的隱形成本要先算清楚

技術跑通只是一半。雙倉架構會帶來三筆持續成本:英國倉的最低月費與存儲費、兩地退貨處理(英國退貨若寄回香港,運費常高於商品毛利)、以及每月的 VAT 申報。務實的做法是先用香港直寄跑 3–6 個月,累積英國市場的 SKU 流速數據,再決定把哪 50–100 個 SKU 前置到英國倉,而不是一開始就鋪全品項。

這也是亞太團隊的結構性優勢所在:香港與英國有 7–8 小時時差(夏令時 7 小時),香港上午處理的補貨指令,英國倉開工時已在隊列中;反過來英國晚間的訂單,香港次日上午就能安排直寄。若團隊分佈在香港、台北與新加坡,覆蓋範圍還能延伸到澳洲與東南亞市場的營運窗口。這對美國或歐洲品牌要進亞洲、或亞洲品牌要進歐洲,都是同一套邏輯。

Ready to Transform Your Ecommerce Operations?

Branch8 specializes in ecommerce platform implementation and AI-powered automation solutions. Contact us today to discuss your ecommerce automation strategy.

用 LLM 輔助多倉營運的兩個實際用法

我們在為一家香港多品牌零售集團規劃跨境倉同步時,把兩段人工作業交給了 LLM 輔助處理,機制值得參考:

  1. SKU 對照表清洗:3PL 給的商品描述常與 ERP 主檔不一致(大小寫、顏色寫法、包裝單位)。用 LLM 產生候選對照,再由人工只覆核低信心度的那一批,而不是全表人工比對。關鍵是把 LLM 的輸出當作「待審清單」而非「最終答案」。
  2. 同步失敗日誌分類:把 userErrors 與 webhook 失敗日誌餵給一個分類提示,自動歸類為「權限」「未啟用 location」「數量衝突」「上游資料缺失」四類,並附上建議動作。營運人員早上看到的是分好類的待辦,而不是一萬行 JSON。

這兩者都不取代同步邏輯本身——庫存同步必須是決定性的、可重放的程式碼,不應由模型決定數字。LLM 的價值在它周邊的整理與判讀工作。

需要協助落地這套架構嗎?

Branch8 總部位於香港,交付團隊分佈於新加坡、台灣、越南、馬來西亞、印尼、菲律賓與澳洲,專注 Shopify Plus 建置、遷移與跨境營運整合。如果你正在規劃本地倉 + 海外倉的庫存同步、ERP 對接或 Shopify Markets 稅務設定,歡迎與我們談談你的 SKU 結構與出貨模式,我們會先幫你判斷雙倉架構現在是否值得做。

Ready to Transform Your Ecommerce Operations?

Branch8 specializes in ecommerce platform implementation and AI-powered automation solutions. Contact us today to discuss your ecommerce automation strategy.

Sources

FAQ

根據 Shopify Help Center 的 Locations 文件,Shopify Plus 方案最多支援 1,000 個庫存地點,而基本方案上限為 10 個。對香港品牌而言,這足以涵蓋自營中央倉、多個海外 3PL、實體門市與寄售點,但實務上建議只將真正會備貨的地點設為 stocked,避免訂單路由把零庫存地點列為候選。

About the Author

Matt Li

Co-Founder & CEO, Branch8 & Second Talent

Matt Li is Co-Founder and CEO of Branch8, a Y Combinator-backed (S15) Adobe Solution Partner and e-commerce consultancy headquartered in Hong Kong, and Co-Founder of Second Talent, a global tech hiring platform ranked #1 in Global Hiring on G2. With 12 years of experience in e-commerce strategy, platform implementation, and digital operations, he has led delivery of Adobe Commerce Cloud projects for enterprise clients including Chow Sang Sang, HomePlus (HKBN), Maxim's, Hong Kong International Airport, Hotai/Toyota, and Evisu. Prior to founding Branch8, Matt served as Vice President of Mid-Market Enterprises at HSBC. He serves as Vice Chairman of the Hong Kong E-Commerce Business Association (HKEBA). A self-taught software engineer, Matt graduated from the University of Toronto with a Bachelor of Commerce in Finance and Economics.