Shopify REST API 轉接器
相容於 Admin API
最後更新:2026年9月5日
一套可直接替換的 STOAR REST API,完整比照 Shopify Admin REST API 2024-01——相同的 URL 路徑(/admin/api/2024-01/...)、相同的扁平查詢參數語法、相同的 JSON 封裝結構({ "order": {…} }、{ "orders": [...] })、相同的驗證標頭、相同的 Link: <…>; rel="next" 游標分頁。既有的 Shopify 用戶端函式庫(shopify_api Ruby gem、@shopify/shopify-api-node、ShopifySharp、python-shopify-api)不需修改即可與 STOAR 溝通。
本轉接器是 STOAR 可擴充的 API 轉接器框架 的第三個實作(繼 Magento 與 WooCommerce 之後)。它示範了另一種截然不同的封裝風格——頂層具名包裝加上游標分頁——與 Magento、WC 並存於同一個與廠商無關的資料層之上。
目錄 #
快速開始 #
TOKEN="4|abcdef…" # Sanctum personal-access token with shopify:admin ability
# Discover shop currency / locale (real Shopify clients call this first)
curl -H "X-Shopify-Access-Token: $TOKEN" \
"https://app.stoar.ai/admin/api/2024-01/shop.json" | jq '.shop | {name, currency}'
# List the most recent 5 orders
curl -H "X-Shopify-Access-Token: $TOKEN" \
"https://app.stoar.ai/admin/api/2024-01/orders.json?limit=5" | jq '.orders[] | {id, financial_status, total_price}'
# Fetch a single order
curl -H "X-Shopify-Access-Token: $TOKEN" \
"https://app.stoar.ai/admin/api/2024-01/orders/10126.json"
# Cancel a pending order
curl -X POST -H "X-Shopify-Access-Token: $TOKEN" \
"https://app.stoar.ai/admin/api/2024-01/orders/123/cancel.json" \
-H "Content-Type: application/json" -d '{"reason":"customer"}'
也可以使用 Bearer 驗證——-H "Authorization: Bearer $TOKEN" 與 Shopify 原生標頭可互換使用。
驗證 #
Shopify 的標準驗證標頭是 X-Shopify-Access-Token: <token>。STOAR 的轉接器同時接受它與 Bearer 備援方式:
| 方式 | 格式 | 使用情境 |
|---|---|---|
| X-Shopify-Access-Token | X-Shopify-Access-Token: <sanctum-token> |
所有 Shopify 用戶端函式庫的預設做法 |
| Bearer (STOAR 擴充) | Authorization: Bearer <sanctum-token> |
原生 Sanctum——與 Magento 轉接器的驗證方式可互換 |
權杖可從 STOAR 的 /manager/api-tokens 頁面核發,也可以用程式呼叫 AdminUser::createToken('label', ['shopify:admin']),或者——針對 STOAR 內部流程——透過 Magento 的 /rest/V1/integration/admin/token 端點取得,再於同一筆記錄上授予 shopify:admin 能力。
對應到 Sanctum。 AccessTokenMiddleware 會在 auth:sanctum 之前執行,把 X-Shopify-Access-Token 轉為 Authorization: Bearer … 標頭。從 STOAR 的角度看,每個 Shopify 請求都只是一般的 Sanctum 驗證請求,其權杖記錄帶有 shopify:admin 能力。單一權杖可以同時持有所有轉接器的能力(shopify:admin + magento:admin + woocommerce:admin + bigcommerce:admin)。
不支援 OAuth 與 HMAC 驗證(真正的 Shopify app 所使用的機制)。
端點 #
所有路徑都相對於 /admin/api/2024-01(原封不動沿用 Shopify API 命名空間,含 2024-01 版本號)。
GET /admin/api/2024-01/shop.json
回傳由 STOAR Setting 資料表合成的商店中繼資料。真正的 Shopify 用戶端會先呼叫這個端點,取得商店的幣別與語系後才進行其他動作。
回應:
{
"shop": {
"id": 1,
"name": "STOAR",
"domain": "app.stoar.ai",
"myshopify_domain": "app.stoar.ai",
"email": "[email protected]",
"currency": "EUR",
"country_code": "DE",
"country_name": "Germany",
"primary_locale": "en",
"iana_timezone": "UTC",
"weight_unit": "kg",
"plan_name": "stoar",
"plan_display_name":"STOAR",
"shop_owner": "STOAR",
"money_format": "€ {{amount}}",
"checkout_api_supported": true,
"has_storefront": true,
"..."
}
}
GET /admin/api/2024-01/orders.json
列出訂單。
Authorization: shopify:admin。
查詢: 見查詢參數。
回應(200):
HTTP/1.1 200 OK
Link: <…?page_info=eyJwIjoyLCJzIjo1LCJmIjoiZjE…&limit=5>; rel="next"
Content-Type: application/json
{
"orders": [
{ /* order object — see Response shape */ }
]
}
分頁由 Link 標頭驅動(沒有 ?page= 計數器)。見游標分頁。
GET /admin/api/2024-01/orders/{id}.json
依數值 id 取得單一訂單。
回應: { "order": {...} } 封裝。見回應結構。
錯誤:
{ "errors": "Not Found" }
POST /admin/api/2024-01/orders/{id}/cancel.json
取消一筆待付款或已付款的訂單。
Authorization: shopify:admin。
內容(選填):
{ "reason": "customer" }
Shopify 接受的原因代碼:customer、inventory、fraud、declined、other。STOAR 會將它記錄在產生的 OrderStatusLog 上,但不會據此執行其他動作。
回應(200): 以標準封裝回傳已取消的訂單。
錯誤:
404— id 不存在422— 訂單處於不允許取消的狀態(例如delivered、refunded)
GET /admin/api/2024-01/products.json
列出商品。封裝格式與 Link 標頭分頁皆與訂單相同。
GET /admin/api/2024-01/products/{id}.json
單一商品。變體會直接內嵌(不只是 id,而是完整的變體物件),與 Shopify 的約定完全一致。
回應: { "product": {...} }。見回應結構。
查詢參數 #
Shopify 的 REST 列表端點採用扁平查詢參數——遠比 Magento 巢狀的 searchCriteria[…] 簡單。解析器位於 app/Api/Adapters/Shopify/Search/。
共用參數(訂單與商品)
| 參數 | 預設值 | 用途 |
|---|---|---|
limit |
50 |
每頁筆數(上限 250) |
page_info |
— | 不透明的 base64 游標——會覆寫其他所有篩選條件(見游標分頁) |
since_id |
— | 只回傳 id > since_id 的項目(游標的替代方案) |
ids |
— | 以逗號分隔的 id 清單(?ids=1,2,3) |
created_at_min / created_at_max |
— | ISO 8601 |
updated_at_min / updated_at_max |
— | ISO 8601 |
order |
created_at desc |
<field> <direction>。方向:asc / desc |
僅適用於訂單
| 參數 | 範例 | 效果 |
|---|---|---|
status |
open、closed、cancelled、any |
高層次的生命週期——會轉換成多個 Stoar 狀態 |
financial_status |
paid、pending、refunded、voided、authorized |
轉換成單一 Stoar 狀態 |
fulfillment_status |
fulfilled、partial、unfulfilled、any |
轉換成 Stoar 狀態 |
僅適用於商品
| 參數 | 範例 | 效果 |
|---|---|---|
status |
active、archived、draft |
轉換成 Stoar 的 active / inactive |
title |
widget |
對商品 name 做子字串(LIKE)比對 |
handle |
widget-pro |
對 slug 做完全比對 |
vendor / product_type |
— | 接受但忽略——Stoar 沒有對應欄位 |
未知的參數會被忽略。無法轉換成任何合理意義的篩選值(例如 ?financial_status=foo)會被靜默丟棄。
游標分頁 #
Shopify 使用不透明的 base64 游標,而非頁碼計數器。STOAR 比照相同約定:
- 用戶端送出
?limit=N(不帶page參數)。 - 伺服器回傳前 N 筆項目,並附上
Link:標頭:Link: <…/orders.json?page_info=eyJwIjoyLCJzIjo1LCJmIjoiYWJjMTIzIn0&limit=5>; rel="next" - 用戶端原封不動地跟隨
rel="next"的 URL——絕不自行組裝。 - 跟隨該連結後,伺服器解碼
page_info得到(page=2, page_size=5, filter_hash=abc123),並回傳下一頁。
filter_hash 是對原始篩選條件集合計算出的穩定 MD5。若用戶端試圖把游標用在不同的結果集上(例如把 ?status=open 改成 ?status=closed),游標的雜湊值就會不符,STOAR 會退回到全新的第 1 頁結果。這與真正 Shopify 的行為一致——參數變動會使游標失效。
Link 標頭可能同時包含 rel="next" 與 rel="previous":
Link: <…?page_info=PREV>; rel="previous", <…?page_info=NEXT>; rel="next"
欄位對應(Shopify ↔ STOAR) #
訂單
| Shopify 欄位 | STOAR 來源 | 備註 |
|---|---|---|
id |
id |
數值 |
admin_graphql_api_id |
id(格式化後) |
gid://shopify/Order/{id} |
name |
id |
#{id}(Shopify 在訂單上顯示 #1001) |
number |
id |
數值 |
order_number |
id + 1000 |
Shopify 預設從 1000 起算 |
email、contact_email |
customer_email |
|
phone |
— | 永遠為 null(Stoar 的 Order 不儲存) |
currency、presentment_currency |
currency(轉大寫) |
eur → EUR |
financial_status |
status(轉換後) |
見狀態轉換 |
fulfillment_status |
status(轉換後) |
null、partial 或 fulfilled |
status(生命週期) |
status(轉換後) |
open、closed、cancelled |
total_price、current_total_price |
total_amount |
兩位小數字串 |
total_price_set |
包住 total_amount 的 money_set |
{shop_money, presentment_money} |
subtotal_price、total_line_items_price |
subtotal |
兩位小數字串 + money_set |
total_tax、current_total_tax |
tax_amount |
兩位小數字串 + money_set |
total_shipping_price_set |
包住 shipping_amount 的 money_set |
|
total_discounts |
discount_amount |
兩位小數字串 |
total_outstanding |
total_amount - sum(succeeded payments) |
尚欠金額 |
total_paid |
不在頂層開放(Shopify 由交易紀錄計算) | 可用 current_total_price - total_outstanding 取得 |
gateway、payment_gateway_names[] |
第一筆未封存的 OrderPayment.gateway |
|
created_at、updated_at、processed_at |
created_at、updated_at |
ISO 8601 |
cancelled_at |
狀態為 cancelled 時取 updated_at |
否則為 null |
closed_at |
狀態為 delivered/refunded 時取 updated_at |
否則為 null |
cancel_reason |
已取消時為 'other' |
否則為 null |
customer |
內嵌的 Customer 模型 |
訪客訂單為 null |
billing_address |
billing_info JSON 欄位 |
Shopify 的扁平結構 |
shipping_address |
shipping_info JSON 欄位 |
Shopify 的扁平結構 |
line_items[] |
Order.items(含變體與商品) |
見下方 |
discount_codes[] |
由 coupon_code 與 discount_amount 推導 |
沒有優惠券時為空 |
tax_lines[] |
tax_amount > 0 時有一個元素 |
稅率為 0,因為 Stoar 不在訂單層級儲存稅率 |
shipping_lines[] |
由 shipping_method 與 shipping_amount 推導 |
沒有配送時為空 |
refunds[] |
refunded_amount > 0 時合成一筆項目 |
|
token |
lookup_token |
訂單的 magic link 權杖——請妥善保密 |
order_status_url |
/checkout/success?order_id=…&token=… |
用戶端用它提供自助查詢訂單的功能 |
tags |
"" |
未建模 |
訂單 line_item
| Shopify 欄位 | STOAR 來源 |
|---|---|
id |
OrderItem.id |
variant_id |
OrderItem.variant_id |
product_id |
OrderItem.product_id |
title |
OrderItem.name |
variant_title |
Variant.name(非 "Default" 時) |
name |
變體有名稱時為 "{title} - {variant_title}" |
sku |
優先取變體 SKU,否則回退到商品 SKU |
quantity |
OrderItem.quantity |
price |
OrderItem.price(兩位小數字串) |
price_set |
money_set 包裝 |
tax_lines[] |
tax_amount > 0 時有一個元素 |
vendor、properties[] |
永遠為空/null |
fulfillment_service |
'manual' |
fulfillment_status |
null |
gift_card、requires_shipping、taxable |
合理的預設值 |
商品
| Shopify 欄位 | STOAR 來源 | 備註 |
|---|---|---|
id |
id |
|
admin_graphql_api_id |
gid://shopify/Product/{id} |
|
title |
name |
|
handle |
slug |
|
body_html |
description |
原樣傳遞(HTML 或純文字) |
status |
status(轉換後) |
active ↔ active;inactive ↔ archived |
vendor、product_type |
永遠是 "" |
Stoar 未建模 |
published_at |
啟用時為 created_at |
停用/封存時為 null |
tags |
"" |
未建模 |
variants[] |
內嵌——完整的變體物件 | 永遠至少一個(Stoar 沒有變體時為 Default Title) |
options[] |
由變體 attributes JSON 的鍵推導(最多 3 個) |
每個選項包含 name、position、values[] |
images[] |
image_path 加上 gallery_paths 陣列 |
position 從 1 起算 |
image |
第一張圖片(或 null) | |
template_suffix、published_scope |
null、'web' |
寫死 |
商品變體
| Shopify 欄位 | STOAR 來源 |
|---|---|
id |
Variant.id |
product_id |
Variant.product_id |
title |
Variant.name(名稱為 "Default" 時輸出 "Default Title") |
option1、option2、option3 |
以穩定順序取自 attributes JSON 的值(最多 3 個軸) |
price |
Variant.price(兩位小數字串) |
sku |
Variant.sku |
inventory_quantity |
Variant.stock |
inventory_management |
'shopify'(固定) |
inventory_policy |
'deny'(固定) |
weight |
Variant.weight |
weight_unit |
'kg' |
grams |
weight * 1000(四捨五入) |
requires_shipping、taxable |
永遠是 true |
compare_at_price |
永遠是 null |
barcode |
永遠是 null |
狀態轉換 #
Shopify 把訂單狀態拆成三個欄位,Stoar 則收攏成一個。轉換器負責雙向處理。
Stoar → Shopify(輸出)
Stoar status |
financial_status |
fulfillment_status |
status(生命週期) |
|---|---|---|---|
pending |
pending |
null |
open |
paid |
paid |
null |
open |
processing |
paid |
partial |
open |
shipped |
paid |
fulfilled |
open |
delivered |
paid |
fulfilled |
closed |
cancelled |
voided |
null |
cancelled |
refunded |
refunded |
null |
closed |
Shopify 篩選 → Stoar(解析)
| Shopify 輸入 | 對應的 Stoar 狀態 |
|---|---|
?status=open |
pending、paid、processing、shipped |
?status=closed |
delivered、refunded |
?status=cancelled |
cancelled |
?status=any |
(不篩選) |
?financial_status=pending |
pending |
?financial_status=paid / =authorized |
paid |
?financial_status=voided |
cancelled |
?financial_status=refunded / =partially_refunded |
refunded |
?fulfillment_status=fulfilled |
shipped |
?fulfillment_status=partial |
processing |
?fulfillment_status=unfulfilled |
paid |
商品狀態
| Shopify | Stoar |
|---|---|
active |
active |
archived、draft |
inactive |
Stoar 沒有 draft 的概念——Shopify 的 archived 與 draft 商品都對應到 Stoar 的 inactive。輸出時一律使用 archived。
回應結構 #
訂單——附註解的範例
{
"order": {
"id": 12345,
"admin_graphql_api_id": "gid://shopify/Order/12345",
"name": "#12345",
"number": 12345,
"order_number": 13345,
"token": "abc123…",
"email": "[email protected]",
"contact_email": "[email protected]",
"currency": "EUR",
"presentment_currency": "EUR",
"financial_status": "paid",
"fulfillment_status": null,
"status": "open",
"gateway": "stripe",
"payment_gateway_names":["stripe"],
"total_price": "115.00",
"total_price_set": {
"shop_money": { "amount": "115.00", "currency_code": "EUR" },
"presentment_money": { "amount": "115.00", "currency_code": "EUR" }
},
"subtotal_price": "100.00",
"total_tax": "10.00",
"total_shipping_price_set": {
"shop_money": { "amount": "5.00", "currency_code": "EUR" },
"presentment_money": { "amount": "5.00", "currency_code": "EUR" }
},
"total_discounts": "0.00",
"total_outstanding": "0.00",
"total_tip_received": "0.00",
"created_at": "2026-04-10T09:00:00+00:00",
"updated_at": "2026-04-10T09:30:00+00:00",
"processed_at": "2026-04-10T09:00:00+00:00",
"cancelled_at": null,
"closed_at": null,
"cancel_reason": null,
"customer": {
"id": 45,
"email": "[email protected]",
"first_name": "Jane",
"last_name": "Doe",
"verified_email": true,
"state": "enabled",
"currency": "EUR"
},
"billing_address": {
"first_name": "Jane",
"last_name": "Doe",
"name": "Jane Doe",
"address1": "1 Test St",
"address2": null,
"city": "Berlin",
"province": null,
"country": null,
"country_code": "DE",
"zip": "10115",
"phone": null
},
"shipping_address": { /* same shape as billing */ },
"line_items": [
{
"id": 987,
"variant_id": 12,
"product_id": 456,
"title": "Widget",
"variant_title":"Red",
"name": "Widget - Red",
"sku": "WID-RED",
"quantity": 2,
"price": "50.00",
"price_set": {"shop_money": {"amount": "50.00", "currency_code": "EUR"}, "presentment_money": {"amount": "50.00", "currency_code": "EUR"}},
"fulfillable_quantity": 2,
"fulfillment_service": "manual",
"fulfillment_status": null,
"requires_shipping": true,
"taxable": true,
"tax_lines": []
}
],
"shipping_lines": [
{
"id": 0,
"title": "Standard",
"code": "flat_rate",
"source": "shopify",
"price": "5.00",
"price_set": {"shop_money": {"amount": "5.00", "currency_code": "EUR"}, "presentment_money": {"amount": "5.00", "currency_code": "EUR"}},
"tax_lines": [],
"discount_allocations": []
}
],
"tax_lines": [],
"discount_codes": [],
"discount_applications":[],
"fulfillments": [],
"refunds": []
}
}
商品——精簡範例
{
"product": {
"id": 789,
"admin_graphql_api_id":"gid://shopify/Product/789",
"title": "Widget",
"body_html": "<p>A great widget</p>",
"vendor": "",
"product_type": "",
"handle": "widget",
"status": "active",
"published_at": "2026-04-01T10:00:00+00:00",
"published_scope": "web",
"tags": "",
"variants": [
{
"id": 12,
"admin_graphql_api_id":"gid://shopify/ProductVariant/12",
"product_id": 789,
"title": "Red",
"price": "99.99",
"sku": "WID-RED",
"position": 1,
"inventory_policy": "deny",
"compare_at_price": null,
"fulfillment_service":"manual",
"inventory_management":"shopify",
"option1": "Red",
"option2": null,
"option3": null,
"weight": 0.5,
"weight_unit": "kg",
"grams": 500,
"inventory_quantity": 42
}
],
"options": [
{ "id": 0, "product_id": 789, "name": "Color", "position": 1, "values": ["Red", "Blue"] }
],
"images": [
{
"id": 0,
"admin_graphql_api_id": "gid://shopify/ProductImage/0",
"product_id": 789,
"position": 1,
"alt": null,
"src": "products/widget.webp",
"variant_ids":[]
}
],
"image": { /* same shape as images[0] */ }
}
}
實際範例 #
對正式環境送出 GET /admin/api/2024-01/orders/10126.json(同一筆在 Magento 與 WooCommerce 文件中出現的訂單,以 Shopify 結構即時轉換)。個資已匿名化。這份回應可直接餵給 Shopify 的 shopify_api Ruby gem 與 @shopify/shopify-api-node,不需任何修改。
{
"order": {
"id": 10126,
"admin_graphql_api_id": "gid://shopify/Order/10126",
"name": "#10126",
"number": 10126,
"order_number": 11126,
"token": "REDACTED-FOR-DOCS",
"email": "[email protected]",
"contact_email": "[email protected]",
"currency": "USD",
"presentment_currency": "USD",
"financial_status": "paid",
"fulfillment_status": null,
"status": "open",
"gateway": "payid",
"payment_gateway_names":["payid"],
"total_price": "936.98",
"subtotal_price": "936.98",
"total_tax": "0.00",
"total_outstanding": "936.98",
"total_price_set": { "shop_money": { "amount": "936.98", "currency_code": "USD" }, "presentment_money": { "amount": "936.98", "currency_code": "USD" } },
"created_at": "2025-06-03T04:56:43+00:00",
"updated_at": "2025-06-03T04:56:43+00:00",
"processed_at": "2025-06-03T04:56:43+00:00",
"cancelled_at": null,
"closed_at": null,
"billing_address": {
"first_name": "Jane",
"last_name": "Doe",
"name": "Jane Doe",
"address1": "1 Example Street",
"address2": null,
"city": "Phoenix",
"province": "AZ",
"country": null,
"country_code": "US",
"zip": "85001",
"phone": "+1-555-0100"
},
"shipping_address": { /* same shape */ },
"customer": {
"id": 5794,
"email": "[email protected]",
"first_name": "Jane",
"last_name": "Doe",
"state": "enabled",
"verified_email": true,
"currency": "USD"
},
"line_items": [
{
"id": 30219,
"variant_id": 95589,
"product_id": 112238,
"title": "Reloop Terminal Mix 8",
"variant_title":null,
"name": "Reloop Terminal Mix 8",
"sku": "RELOOP_TERMINALMIX8_025-DEF",
"quantity": 3,
"price": "299.00",
"fulfillable_quantity": 3,
"fulfillment_service": "manual",
"fulfillment_status": null,
"requires_shipping": true,
"taxable": false,
"tax_lines": []
},
{
"id": 30220,
"variant_id": 33857,
"product_id": 51706,
"title": "Premium Skateboard Socks",
"variant_title":null,
"name": "Premium Skateboard Socks",
"sku": "SK8-SOCK-027-DEF",
"quantity": 2,
"price": "19.99",
"fulfillable_quantity": 2,
"fulfillment_service": "manual",
"fulfillment_status": null,
"requires_shipping": true,
"taxable": false,
"tax_lines": []
}
],
"shipping_lines": [{
"id": 0,
"title": "Free Shipping",
"code": "flat_rate",
"source": "shopify",
"price": "0.00"
}],
"tax_lines": [],
"discount_codes": [],
"discount_applications":[],
"fulfillments": [],
"refunds": []
}
}
整合人員應留意的事項
| 欄位 | 觀察到的值 | 原因 |
|---|---|---|
total_outstanding |
已付款訂單卻是 "936.98" |
由 OrderPayment 稽核記錄計算;早於該記錄的舊訂單會把完整總額顯示為未付金額。 |
gateway |
"payid" |
這是 Stoar 的 gateway key——不是像 shopify_payments 那樣的 Shopify 標準名稱。 |
customer_locale、device_id、app_id |
永遠是 null |
Stoar 的 Order 未建模。 |
tax_lines |
即使 total_tax > 0 仍是 [] |
Stoar 只在訂單層級記錄稅額,不分稅務轄區;必要時我們才會合成單一 tax_line。 |
fulfillments、discount_applications |
永遠是 [] |
沒有出貨追蹤;優惠券只以扁平的 discount_codes 表示。 |
tags |
永遠是 "" |
Stoar 沒有標籤系統。 |
token |
每筆訂單專屬的 magic link 權杖 | 切勿曝露於用戶端程式碼或記錄中——只要持有這個權杖,不需驗證即可檢視該訂單。 |
order_number |
id + 1000 |
純屬外觀——Shopify 所有商店預設都從 1000 起算。 |
錯誤結構 #
Shopify 採用較寬鬆的封裝格式:
{ "errors": "Not Found" } // string
{ "errors": { "title": ["can't be blank"] } } // map (validation)
| HTTP | 觸發原因 | 內容 |
|---|---|---|
| 401 | 缺少權杖或權杖無效 | { "errors": "[API] Invalid API key or access token …" } |
| 403 | 權杖能力不符 | { "errors": "Forbidden" } |
| 404 | 資源 id 不存在 | { "errors": "Not Found" } |
| 422 | 前置條件不符(取消不可取消的訂單等) | { "errors": "Order N cannot be cancelled in status 'delivered'." } |
| 429 | 超過流量限制 | { "errors": "Exceeded 2 calls per second for api client. …" } 加上 Retry-After: 2 |
| 500 | 非預期的伺服器錯誤 | { "errors": "Internal Server Error" } |
驗證錯誤(只有 cancel.json 接受內容)採用以欄位為鍵的 map 結構。
流量限制 #
保護 Magento 與 WooCommerce 的那套以 Sanctum 權杖為鍵的 api-rest 節流機制,同樣保護 Shopify 路由。兩者都在 /manager/api-settings 統一設定。觸發時,回應會使用 Shopify 的錯誤封裝:
HTTP/1.1 429 Too Many Requests
Retry-After: 2
Content-Type: application/json
{ "errors": "Exceeded 2 calls per second for api client. Reduce request rates to resume uninterrupted service." }
Retry-After 標頭的值與 Shopify 文件描述的行為一致。真正的 Shopify 使用漏桶演算法;STOAR 使用滑動視窗的分鐘桶——對用戶端函式庫的相容性而言已相當接近。
同一個 Sanctum 權杖若跨全部四個轉接器(Magento + WC + Shopify + BC)使用,會共用同一個桶——完整的設定介面操作說明請見 Magento 文件的流量限制章節。
延伸閱讀 #
app/Api/Adapters/Shopify/Support/StatusTranslator.php— 雙向的詞彙對應app/Api/Adapters/Shopify/Support/PageInfoCursor.php— 不透明 base64 游標的編碼- Shopify Admin REST API 參考文件 — 本轉接器所比照的上游規格