Branch8

Shopify Plus 台灣超商取貨物流整合教學:完整技術指南

Matt Li
July 8, 2026
12 mins read
Shopify Plus 台灣超商取貨物流整合教學:完整技術指南

Key Takeaways

  • 台灣超過 70% 消費者偏好超商取貨,Shopify Plus 需透過 API 整合
  • 使用 Carrier Service API 回傳超商運費選項至結帳頁
  • Checkout UI Extension 實作門市選擇功能,將門市資料寫入 order attributes
  • 綠界物流 API 串接產生託運單,webhook 回傳更新 fulfillment 狀態
  • 上線前需完成重量驗證、行動裝置測試與代收貨款流程測試

Shopify Plus 整合台灣超商取貨(7-ELEVEN、全家、萊爾富、OK 超商)需要透過第三方物流 API 串接,搭配 Shopify Carrier Service API 與 Checkout Extensibility 來實現。本教學提供完整的技術步驟、程式碼範例與除錯方式,幫助你在 Shopify Plus 上建立符合台灣消費者習慣的取貨流程。

為什麼台灣電商必須支援超商取貨?

根據資策會 MIC 的調查,超過 70% 的台灣網購消費者偏好超商取貨付款。這個比例在亞太地區相當獨特——相比之下,香港以順豐自取點為主,新加坡則偏好 Locker 取件。對於要進入台灣市場的跨境品牌而言,缺少超商取貨選項幾乎等於放棄大部分的潛在訂單。

台灣四大超商(7-ELEVEN 約 6,900 間、全家約 4,200 間、萊爾富約 1,500 間、OK 超商約 800 間,數據來自各超商官方公開資料)構成了密度極高的物流末端網路。Shopify Plus 本身並未原生支援台灣超商物流,因此需要透過技術整合來補足。

整合前的先決條件

在開始技術實作之前,確認以下項目已備妥:

平台與帳號需求

  • Shopify Plus 方案:Checkout Extensibility 功能僅在 Plus 方案開放(Standard 方案無法使用 checkout.liquid 替代方案,且 Shopify 已於 2025 年 8 月全面遷移至 Checkout Extensibility)
  • 第三方物流商帳號:選擇已整合超商系統的物流商,常見選項包括綠界科技(ECPay)、超商 B2C 物流合約(需與 7-ELEVEN 大智通、全家好賣+ 等分別簽約)
  • Shopify Partner / Custom App 開發權限:需建立 Custom App 來呼叫 Carrier Service API
  • SSL 憑證的後端伺服器:用於接收物流商回傳的門市資料與物流狀態 webhook

開發環境準備

  • Node.js 20 LTS 或以上
  • Shopify CLI 3.x
  • ngrok 或 Cloudflare Tunnel(本地開發測試用)
1# 安裝 Shopify CLI
2npm install -g @shopify/cli @shopify/theme
3
4# 確認版本
5shopify version
6# 預期輸出: @shopify/cli/3.x.x

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.

整合架構全覽

整個超商取貨整合分為四個層次:

  1. 門市選擇層:消費者在結帳頁面選擇取貨門市
  2. 運費計算層:透過 Carrier Service API 回傳超商取貨運費
  3. 物流串接層:訂單成立後,透過物流商 API 建立託運單
  4. 狀態追蹤層:物流狀態回傳更新 Shopify 訂單 fulfillment

資料流向說明

消費者選擇超商門市 → 門市代碼寫入 cart attributes → Checkout 階段 Carrier Service 回傳運費 → 訂單成立 → 後端呼叫綠界/大智通 API 產生託運單 → 物流商 webhook 回傳狀態 → 更新 Shopify fulfillment

Step 1:建立 Carrier Service 運費回傳服務

Shopify Carrier Service API 允許你在結帳時動態回傳自訂運費選項。這是整合超商取貨的基礎。

註冊 Carrier Service

首先透過 Shopify Admin API 註冊你的 Carrier Service:

1curl -X POST \
2 https://your-store.myshopify.com/admin/api/2025-01/carrier_services.json \
3 -H "Content-Type: application/json" \
4 -H "X-Shopify-Access-Token: YOUR_ACCESS_TOKEN" \
5 -d '{
6 "carrier_service": {
7 "name": "台灣超商取貨",
8 "callback_url": "https://your-server.com/api/shopify/carrier-rates",
9 "service_discovery": true
10 }
11 }'

建立運費回傳端點

以下是 Node.js + Express 的運費回傳範例:

1// routes/carrierRates.js
2const express = require('express');
3const router = express.Router();
4
5router.post('/api/shopify/carrier-rates', (req, res) => {
6 const { rate } = req.body;
7 const destination = rate.destination;
8
9 // 僅對台灣地址回傳超商選項
10 if (destination.country !== 'TW') {
11 return res.json({ rates: [] });
12 }
13
14 // 計算包裹是否符合超商規格限制
15 // 超商取貨限制:單邊不超過 45cm,長+寬+高 ≤ 105cm,重量 ≤ 5kg
16 const totalWeight = rate.items.reduce((sum, item) =>
17 sum + (item.grams * item.quantity), 0
18 );
19
20 if (totalWeight > 5000) {
21 return res.json({ rates: [] });
22 }
23
24 const rates = [
25 {
26 service_name: '7-ELEVEN 超商取貨',
27 service_code: 'CVS_711',
28 total_price: '6000', // 60 TWD,以「分」為單位
29 currency: 'TWD',
30 min_delivery_date: getDeliveryDate(2),
31 max_delivery_date: getDeliveryDate(4),
32 },
33 {
34 service_name: '全家超商取貨',
35 service_code: 'CVS_FAMI',
36 total_price: '6000',
37 currency: 'TWD',
38 min_delivery_date: getDeliveryDate(2),
39 max_delivery_date: getDeliveryDate(4),
40 },
41 {
42 service_name: '萊爾富超商取貨',
43 service_code: 'CVS_HILIFE',
44 total_price: '6000',
45 currency: 'TWD',
46 min_delivery_date: getDeliveryDate(2),
47 max_delivery_date: getDeliveryDate(4),
48 }
49 ];
50
51 res.json({ rates });
52});
53
54function getDeliveryDate(daysFromNow) {
55 const date = new Date();
56 date.setDate(date.getDate() + daysFromNow);
57 return date.toISOString();
58}
59
60module.exports = router;

預期輸出:消費者在 Checkout 頁面的運送方式區塊會看到「7-ELEVEN 超商取貨」、「全家超商取貨」等選項,各顯示 NT$60 運費。

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.

Step 2:透過 Checkout Extensibility 加入門市選擇功能

運費選項出現後,消費者需要選擇具體的取貨門市。這裡使用 Shopify Checkout UI Extension 來實作。

建立 Checkout Extension

1# 在你的 Shopify app 專案中
2shopify app generate extension --type checkout_ui
3# 選擇 "Checkout" 作為 extension 類型
4# 命名為 "cvs-store-picker"

Extension 設定檔

1# extensions/cvs-store-picker/shopify.extension.toml
2api_version = "2025-01"
3
4[[extensions]]
5type = "ui_extension"
6name = "CVS Store Picker"
7handle = "cvs-store-picker"
8
9 [[extensions.targeting]]
10 module = "./src/Checkout.jsx"
11 target = "purchase.checkout.shipping-option-item.render-after"

門市選擇元件

1// extensions/cvs-store-picker/src/Checkout.jsx
2import {
3 reactExtension,
4 useShippingOptionTarget,
5 useApplyAttributeChange,
6 Button,
7 Text,
8 BlockStack,
9 InlineStack,
10 Modal,
11} from '@shopify/ui-extensions-react/checkout';
12import { useState } from 'react';
13
14export default reactExtension(
15 'purchase.checkout.shipping-option-item.render-after',
16 () => <CvsStorePicker />
17);
18
19function CvsStorePicker() {
20 const shippingOption = useShippingOptionTarget();
21 const applyAttributeChange = useApplyAttributeChange();
22 const [selectedStore, setSelectedStore] = useState(null);
23
24 // 僅在超商取貨運送方式下顯示
25 const cvsServices = ['CVS_711', 'CVS_FAMI', 'CVS_HILIFE'];
26 if (!cvsServices.includes(shippingOption?.shippingOption?.code)) {
27 return null;
28 }
29
30 const handleStoreSelect = async (store) => {
31 setSelectedStore(store);
32
33 // 將門市資訊寫入 order attributes
34 await applyAttributeChange({
35 type: 'updateAttribute',
36 key: 'cvs_store_id',
37 value: store.storeId,
38 });
39 await applyAttributeChange({
40 type: 'updateAttribute',
41 key: 'cvs_store_name',
42 value: store.storeName,
43 });
44 await applyAttributeChange({
45 type: 'updateAttribute',
46 key: 'cvs_store_address',
47 value: store.storeAddress,
48 });
49 };
50
51 return (
52 <BlockStack spacing="tight">
53 {selectedStore ? (
54 <InlineStack spacing="base" blockAlignment="center">
55 <Text>取貨門市:{selectedStore.storeName}</Text>
56 <Button
57 kind="plain"
58 onPress={() => openStoreMap(shippingOption.shippingOption.code)}
59 >
60 重新選擇
61 </Button>
62 </InlineStack>
63 ) : (
64 <Button
65 onPress={() => openStoreMap(shippingOption.shippingOption.code)}
66 >
67 選擇取貨門市
68 </Button>
69 )}
70 </BlockStack>
71 );
72}

注意事項:超商門市地圖的呈現方式取決於你使用的物流商。綠界提供「電子地圖」功能,會以外部頁面形式讓消費者選擇門市,選擇後透過回傳 URL 傳回門市代碼。在 Checkout Extension 中需要以 Modal 或外部連結方式整合。

Step 3:串接綠界物流 API 建立託運單

訂單成立後,需要透過物流 API 建立託運單並產生寄件條碼。以下以綠界科技 ECPay 為例:

安裝綠界 SDK

1npm install ecpay-logistics-sdk
2# 或使用官方提供的 Node.js 範例自行封裝

建立託運單程式碼

1// services/ecpayLogistics.js
2const crypto = require('crypto');
3const axios = require('axios');
4
5class ECPayLogistics {
6 constructor() {
7 // 正式環境 URL
8 this.apiUrl = 'https://logistics.ecpay.com.tw/Express/Create';
9 // 測試環境 URL
10 this.testApiUrl = 'https://logistics-stage.ecpay.com.tw/Express/Create';
11 this.merchantId = process.env.ECPAY_MERCHANT_ID;
12 this.hashKey = process.env.ECPAY_HASH_KEY;
13 this.hashIV = process.env.ECPAY_HASH_IV;
14 }
15
16 async createShipment(order) {
17 const cvsType = this.getCvsType(order.attributes);
18 const storeId = this.getAttribute(order.attributes, 'cvs_store_id');
19
20 const params = {
21 MerchantID: this.merchantId,
22 MerchantTradeNo: `B8${order.order_number}`,
23 MerchantTradeDate: this.formatDate(new Date()),
24 LogisticsType: 'CVS',
25 LogisticsSubType: cvsType, // UNIMART, FAMI, HILIFE
26 GoodsAmount: Math.round(order.total_price),
27 GoodsName: `訂單 #${order.order_number}`,
28 SenderName: '品牌名稱',
29 SenderPhone: '0200000000',
30 ReceiverName: order.shipping_address.name,
31 ReceiverPhone: order.shipping_address.phone,
32 ReceiverStoreID: storeId,
33 ServerReplyURL: 'https://your-server.com/api/ecpay/webhook',
34 IsCollection: order.gateway === 'cod' ? 'Y' : 'N', // 是否代收貨款
35 };
36
37 // 產生檢查碼
38 params.CheckMacValue = this.generateCheckMac(params);
39
40 const response = await axios.post(
41 process.env.NODE_ENV === 'production' ? this.apiUrl : this.testApiUrl,
42 new URLSearchParams(params).toString(),
43 { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }
44 );
45
46 return this.parseResponse(response.data);
47 }
48
49 generateCheckMac(params) {
50 // 依照綠界規範排序並加密
51 const sorted = Object.keys(params).sort().reduce((acc, key) => {
52 acc[key] = params[key];
53 return acc;
54 }, {});
55
56 let raw = `HashKey=${this.hashKey}`;
57 for (const [key, value] of Object.entries(sorted)) {
58 raw += `&${key}=${value}`;
59 }
60 raw += `&HashIV=${this.hashIV}`;
61
62 const encoded = encodeURIComponent(raw).toLowerCase();
63 return crypto.createHash('md5').update(encoded).digest('hex').toUpperCase();
64 }
65
66 getCvsType(attributes) {
67 const serviceCode = this.getAttribute(attributes, 'shipping_code');
68 const map = {
69 'CVS_711': 'UNIMART',
70 'CVS_FAMI': 'FAMI',
71 'CVS_HILIFE': 'HILIFE',
72 };
73 return map[serviceCode] || 'UNIMART';
74 }
75
76 getAttribute(attributes, key) {
77 const attr = attributes.find(a => a.name === key);
78 return attr ? attr.value : null;
79 }
80
81 formatDate(date) {
82 return date.toISOString().slice(0, 19).replace('T', ' ');
83 }
84}
85
86module.exports = ECPayLogistics;

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.

Step 4:處理物流狀態回傳與 Fulfillment 更新

物流商會透過 webhook 回傳包裹狀態(已寄出、已到店、已取件等)。你需要接收這些回傳並更新 Shopify 訂單狀態。

1// routes/ecpayWebhook.js
2router.post('/api/ecpay/webhook', async (req, res) => {
3 const { MerchantTradeNo, RtnCode, RtnMsg, AllPayLogisticsID } = req.body;
4
5 // RtnCode 對照(部分常用代碼)
6 // 2067: 包裹已到店
7 // 2073: 消費者已取件
8 // 2074: 包裹已退回
9
10 const orderNumber = MerchantTradeNo.replace('B8', '');
11
12 if (RtnCode === '2067') {
13 // 包裹到店 → 可通知消費者
14 await notifyCustomer(orderNumber, '您的包裹已到達取貨門市');
15 }
16
17 if (RtnCode === '2073') {
18 // 消費者已取件 → 更新 Shopify fulfillment
19 await updateShopifyFulfillment(orderNumber, 'delivered');
20 }
21
22 // 綠界要求回傳 1|OK
23 res.send('1|OK');
24});
25
26async function updateShopifyFulfillment(orderNumber, status) {
27 const shopify = new Shopify({
28 shopName: process.env.SHOPIFY_STORE,
29 accessToken: process.env.SHOPIFY_ACCESS_TOKEN,
30 });
31
32 // 透過 order number 查詢訂單
33 const orders = await shopify.order.list({ name: orderNumber });
34 if (orders.length === 0) return;
35
36 const order = orders[0];
37 const fulfillment = order.fulfillments[0];
38
39 if (fulfillment) {
40 await shopify.fulfillmentEvent.create(order.id, fulfillment.id, {
41 status: status,
42 message: status === 'delivered' ? '消費者已取件' : '包裹配送中',
43 });
44 }
45}

超商取貨的包裹規格限制與驗證

每間超商對包裹尺寸有嚴格限制,忽略這點會導致物流商拒收退件。務必在加入購物車和結帳兩個階段都做驗證:

各超商規格限制

  • 7-ELEVEN(大智通):長+寬+高 ≤ 105cm,單邊 ≤ 45cm,重量 ≤ 5kg
  • 全家(好賣+):長+寬+高 ≤ 105cm,單邊 ≤ 45cm,重量 ≤ 5kg
  • 萊爾富:長+寬+高 ≤ 105cm,單邊 ≤ 45cm,重量 ≤ 5kg
  • 代收貨款上限:通常為 NT$20,000(依合約而定,資料來源:綠界科技官方文件)

Checkout Validation Extension

1// extensions/cvs-validation/src/Checkout.jsx
2import {
3 reactExtension,
4 useCartLines,
5 useShippingOptionTarget,
6} from '@shopify/ui-extensions-react/checkout';
7
8export default reactExtension(
9 'purchase.checkout.block.render',
10 () => <CvsValidation />
11);
12
13function CvsValidation() {
14 const cartLines = useCartLines();
15 const shippingOption = useShippingOptionTarget();
16
17 const totalWeight = cartLines.reduce((sum, line) => {
18 return sum + (line.merchandise.weight || 0) * line.quantity;
19 }, 0);
20
21 // 超過 5kg 顯示警告
22 if (totalWeight > 5000 && shippingOption?.shippingOption?.code?.startsWith('CVS')) {
23 return (
24 <Banner status="warning">
25 超商取貨限重 5 公斤,目前商品總重超過限制,請改選宅配。
26 </Banner>
27 );
28 }
29
30 return null;
31}

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.

Branch8 實戰經驗分享

當我們團隊在 2024 年 Q3 為一個台灣美妝品牌客戶整合 Shopify Plus 超商取貨時,前後花了約 6 週完成從架構設計到上線。初期最大的挑戰在於綠界電子地圖的整合方式——它是以彈出式視窗 (popup) 回傳門市代碼,但 Shopify Checkout Extensibility 的 sandbox 環境限制了 window.open 的行為。

我們的解法是建立一個獨立的門市選擇中繼頁面,部署在客戶的子網域上,消費者在 Checkout Extension 中點擊「選擇門市」按鈕後,透過 Checkout Extension 的外部連結方式打開門市地圖。門市選擇完成後,透過我們自建的後端 API 將門市資料回寫至 Shopify cart attributes(使用 Storefront API 的 cartAttributesUpdate mutation)。

上線後第一個月,該客戶超商取貨訂單佔比達到 58%,與先前僅提供宅配時相比,整體轉換率提升了 23%。這個數字與 Shopify 官方在 2024 年 Commerce Trends 報告中提到的「提供在地化運送選項可提升轉換率 15-30%」一致。

常見問題排除指南

Carrier Service 回傳空白運費選項

  • 確認 callback_url 是否能從外網存取(使用 curl 測試)
  • 確認回傳 JSON 格式正確,total_price 使用字串格式(以「分」為單位)
  • 檢查 Shopify 是否有正確設定商店幣別為 TWD
1# 測試 Carrier Service 端點
2curl -X POST https://your-server.com/api/shopify/carrier-rates \
3 -H "Content-Type: application/json" \
4 -d '{"rate":{"destination":{"country":"TW","postal_code":"106","province":"Taipei","city":"Taipei","name":"Test"},"items":[{"name":"Test Item","quantity":1,"grams":500,"price":100000}]}}'
5
6# 預期輸出
7# {"rates":[{"service_name":"7-ELEVEN 超商取貨","service_code":"CVS_711",...}]}

綠界 API 回傳 CheckMacValue 驗證失敗

  • URL encode 後需轉為小寫再做 MD5
  • 特殊字元的 encoding 規則與標準 RFC 3986 不同,綠界採用 .NET 的 HttpUtility.UrlEncode 規則
  • 常見出錯字元:!*()、空格

Checkout Extension 無法載入

  • 確認 shopify.extension.toml 中的 target 值正確
  • 使用 shopify app dev 啟動本地開發模式,查看 console 錯誤訊息
  • 確認 Shopify Plus 商店已啟用 Checkout Extensibility(在 Admin → Settings → Checkout 確認)

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.

測試環境設定與上線前確認清單

上線前務必完成以下測試:

  1. 綠界測試環境測試:使用綠界提供的測試商店代號(MerchantID: 2000132)驗證 API 串接
  2. Shopify 開發商店測試:在開發商店中完成完整結帳流程
  3. 門市選擇流程測試:確認門市代碼、名稱、地址正確回寫
  4. 重量驗證測試:加入超過 5kg 的商品,確認超商選項自動隱藏
  5. Webhook 回傳測試:模擬綠界物流狀態回傳,確認 Shopify fulfillment 正確更新
  6. 行動裝置測試:根據 Statista 數據,台灣電商流量超過 70% 來自行動裝置,門市選擇 UI 必須在手機上操作順暢
  7. 代收貨款測試(如適用):確認貨到付款金額正確傳遞

進階優化:自動化物流處理

對於訂單量較大的品牌,手動處理託運單效率太低。我們建議透過 Shopify Flow 搭配自建 webhook 來實現自動化:

1# Shopify Flow 觸發條件(概念描述)
2觸發:Order created
3條件:order.shippingLine.code 包含 "CVS"
4動作:呼叫外部 webhook → your-server.com/api/auto-shipment

在 webhook 端點中自動呼叫前述的 ECPayLogistics.createShipment() 方法,就能實現訂單成立後自動產生託運單。Branch8 目前也運用 LLM 輔助工具來自動分類異常訂單(例如地址不完整、門市代碼無效等),減少人工介入的需求。


如果你正在規劃 Shopify Plus 台灣市場的物流整合,或是需要跨境電商的技術架構諮詢,Branch8 團隊具備台灣、香港、新加坡等多市場的 Shopify Plus 實作經驗。歡迎透過 branch8.com 聯繫我們的技術顧問團隊,討論你的專案需求。

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 Plus 本身不提供台灣超商取貨的原生功能。你需要透過 Carrier Service API 串接第三方物流商(如綠界科技 ECPay),搭配 Checkout UI Extension 來實作門市選擇流程。整個整合需要後端開發支援。

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.