跳至主要內容

WooCommerce REST API 轉接器

相容於 v3

最後更新:2026年9月5日

一套可直接替換的 STOAR REST API,對應 WooCommerce v3 的線路格式——相同的 URL 路徑(/wp-json/wc/v3/...)、相同的扁平查詢參數語法、相同的 JSON 回應欄位名稱、相同的驗證選項。現有的 WooCommerce 用戶端函式庫(例如 automattic/woocommerce PHP/JS、klarna/woocommerce-rest-api Node)無需修改即可與 STOAR 溝通。

本轉接器是 STOAR 可擴充的 API 轉接器框架的第二個實作(第一個是 Magento)。它示範了一種本質上截然不同的供應商風格——扁平查詢參數而非巢狀 searchCriteria[…]、Basic Auth 而非只有 Bearer、狀態詞彙為 processingcompleted 而非 paiddelivered——如何在同一個資料層上與 Magento 並存。


目錄 #


快速上手 #

# 1. Get a Sanctum token with woocommerce:admin ability — issued via /manager/api-tokens
#    or via the Magento token endpoint (POST /rest/V1/integration/admin/token), then
#    grant the woocommerce:admin ability inside /manager.
TOKEN="2|L5pXj63e881lkgtHPK7Hjozyq7Pb3trHCy0iaDRf76405f72"

# 2. List the last 5 orders (Bearer auth — STOAR extension; works alongside Basic)
curl -s "https://app.stoar.ai/wp-json/wc/v3/orders?per_page=5&orderby=date&order=desc" \
  -H "Authorization: Bearer $TOKEN" \
  | jq '.[] | {id, status, total, currency}'

# 3. Use HTTP Basic just like a real WooCommerce store
curl -s "https://app.stoar.ai/wp-json/wc/v3/products?per_page=3" \
  -u "any-key:$TOKEN"

# 4. Or stuff credentials into the query string (still over HTTPS only)
curl -s "https://app.stoar.ai/wp-json/wc/v3/products?consumer_key=any&consumer_secret=$TOKEN"

驗證 #

WooCommerce 支援三種驗證風格;本轉接器全部接受,並在內部轉換成同一套 Sanctum personal-access-token 檢查。Token 由 STOAR 的 /manager/api-tokens 頁面核發(或以程式方式透過 AdminUser::createToken('label', ['woocommerce:admin']) 產生)。

方式 格式 使用情境
HTTP Basic Authorization: Basic base64(consumer_key:consumer_secret) 多數 WC 用戶端函式庫的預設方式——僅限 HTTPS
查詢參數 ?consumer_key=…&consumer_secret=… 快速用 curl 測試——僅限 HTTPS
Bearer (STOAR 擴充) Authorization: Bearer <token> 原生 Sanctum——可與 Magento 轉接器互換使用

對應到 Sanctum

轉接器會忽略 consumer_key(可以傳入任意字串——"any-key" 就可以)。consumer_secret 必須是一個有效的 Sanctum personal-access token,且其 abilities 陣列包含 woocommerce:admin

這個對應純粹是一層解讀;從 STOAR 的角度來看,每個 WC 請求都只是以 Bearer 驗證的 Sanctum 請求。同一列 personal-access-token 記錄可同時支援:

  • 使用 /rest/V1/orders 的 Magento 用戶端(需要 magento:admin 能力)
  • 使用 /wp-json/wc/v3/orders 的 WooCommerce 用戶端(需要 woocommerce:admin 能力)

您可以核發一個同時具備兩種能力的 token,或分開核發——由您決定。

顧客 token

顧客範圍的端點尚未提供。woocommerce:customer 能力保留供日後使用。


端點 #

所有路徑都相對於 /wp-json/wc/v3(原封不動沿用 WordPress REST 命名空間)。

GET /wp-json/wc/v3/orders

列出訂單。

授權: Bearer/Basic/查詢參數,需具備 woocommerce:admin 能力。

查詢參數:查詢參數

回應(200): 訂單的扁平 JSON 陣列。分頁資訊放在標頭中,不在內文裡:

HTTP/1.1 200 OK
X-WP-Total:      150
X-WP-TotalPages: 8
Content-Type:    application/json

[
  { /* order */ },
  { /* order */ }
]

為什麼用標頭而不是外層結構? 這正是 WooCommerce 的實際慣例——與 Magento 的 {items, search_criteria, total_count} 包裝不同。WC 用戶端函式庫(Automattic 官方的 PHP/JS 用戶端)會讀取 X-WP-Total 來驅動分頁游標。


GET /wp-json/wc/v3/orders/{id}

以數字 id 取得單筆訂單。

回應(200):回應結構

錯誤:

{
  "code":    "woocommerce_rest_shop_order_invalid_id",
  "message": "Invalid shop_order ID.",
  "data":    { "status": 404, "id": 99999 }
}

GET /wp-json/wc/v3/orders/{id}/notes

列出該訂單的狀態歷程記錄,重新整理成 WooCommerce 備註的形式。

回應(200):

[
  {
    "id":               42,
    "author":           "system",
    "date_created":     "2026-04-10T12:00:00+00:00",
    "date_created_gmt": "2026-04-10T12:00:00+00:00",
    "note":             "Payment received",
    "customer_note":    false,
    "_links":           { "self": [...], "collection": [...], "up": [...] }
  }
]

customer_note 恆為 false,因為 Stoar 在資料層級並不區分顧客可見的備註與僅限後台的備註。


POST /wp-json/wc/v3/orders/{id}/notes

新增一則備註(對應為 Stoar 中一筆新的 OrderStatusLog 記錄)。

請求:

{ "note": "Customer phoned to confirm delivery slot" }

customer_note(bool)會被接受,但目前沒有實際作用。

回應(201): 新備註,結構與 GET .../notes 的項目相同。

錯誤:

  • 400 rest_invalid_param——缺少 note
  • 404——未知的訂單 id

GET /wp-json/wc/v3/orders/{id}/refunds

列出某訂單的退款。Stoar 沒有獨立的退款資料表——轉接器會回傳下列兩者之一:

  • refunded_amount === 0 時回傳 [],或
  • 回傳 [{...}],內含一筆合成的退款記錄,其 id === parent_id === order.id
[
  {
    "id":               123,
    "parent_id":        123,
    "date_created":     "2026-04-12T08:00:00+00:00",
    "amount":           "30.00",
    "reason":           "",
    "refunded_by":      0,
    "refunded_payment": true,
    "meta_data":        [],
    "line_items":       [],
    "api_refund":       true
  }
]

POST /wp-json/wc/v3/orders/{id}/refunds

發出退款。會委派給 Stoar 既有的 Order::processRefund(),它再透過 StripeService::processRefund() 呼叫 Stripe。全額退款時 Stoar 會把訂單標記為 refunded,部分退款則累加 refunded_amount

請求:

{ "amount": 30, "reason": "Customer changed mind" }

兩個欄位都是選填。若省略 amount,Stoar 會退還全部剩餘可退金額。

回應(201): 上述結構的退款記錄。

錯誤:

  • 404——未知的訂單 id
  • 422 woocommerce_rest_invalid_state——訂單不可退款(沒有 Stripe payment intent,或狀態不是 paid/processing/shipped/delivered)

GET /wp-json/wc/v3/products

列出商品。

查詢參數:查詢參數

回應(200): 扁平陣列,附 X-WP-TotalX-WP-TotalPages 標頭。


GET /wp-json/wc/v3/products/{id}

數字 id 取得單筆商品(不像 Magento 使用 SKU)。

回應(200):回應結構

錯誤: 404 woocommerce_rest_product_invalid_id


查詢參數 #

WooCommerce 使用扁平的查詢字串參數——遠比 Magento 巢狀的 searchCriteria[…] 文法單純。轉換成同一套與供應商無關的 OrderQueryProductQuery 值物件,是在轉接器的 Search/OrderQueryParserSearch/ProductQueryParser 類別中完成的。

共通參數(訂單 + 商品)

參數 預設值 用途
per_page 10 每頁筆數(上限 100
page 1 頁碼,從 1 起算
orderby date 排序欄位——見下方各資源清單
order desc ascdesc
include 以逗號分隔的 id 清單(?include=1,2,3
exclude 要排除的 id 清單,以逗號分隔
search 子字串比對——見下方各資源說明

僅限訂單

參數 範例 效果
status processing,completed CSV——轉換為 Stoar 狀態值;群組內以 OR 結合
customer 42 customer_id 篩選
after 2024-01-01T00:00:00 created_at >= …
before 2024-12-31T23:59:59 created_at <= …
search jane customer_email 做 LIKE
orderby 可用值 date(預設)、idincludetitle datecreated_attitlecustomer_email

僅限商品

參數 範例 效果
status publishdraft 轉換為 Stoar 的 activeinactive
type simplevariable variable 轉換為 Stoar 的 configurable
featured true / false is_featured 篩選
category 5 單一分類 id
sku WID-1 精確比對
slug widget-pro 精確比對
min_price 10 price >= …
max_price 100 price <= …
search widget 對商品 name 做 LIKE
orderby 可用值 dateidincludetitlepriceslug titlenameslugslug

未知的參數會被靜默忽略(與 WC 行為一致)。無法轉換成合理值的篩選值(例如對商品下 ?status=on-hold)會產生空群組,而不是回傳 400。


欄位對應(WooCommerce ↔ STOAR) #

訂單

WooCommerce 欄位 STOAR 來源 備註
id id 數字
number id(轉為字串) WC 慣例
order_key lookup_token Stoar 每筆訂單的魔法連結 token
status status(已轉換) 狀態轉換
currency currency(轉為大寫) eurEUR
total total_amount 兩位小數字串
cart_taxtotal_tax tax_amount 兩位小數字串
shipping_total shipping_amount 兩位小數字串
discount_total discount_amount 兩位小數字串
customer_id customer_id ?? 0 訪客為 0
customer_note customer_notes
billing.* billing_info JSON 欄位 扁平的 WC 結構
shipping.* shipping_info JSON 欄位 扁平的 WC 結構
payment_method 第一筆未封存的 OrderPayment.gateway 退回使用 Order.payment_method
payment_method_title 由金流商鍵值推導 stripe →「Credit / Debit Card」等
transaction_id stripe_payment_intent_id
date_createddate_modified created_atupdated_at ISO8601
date_paid 第一筆成功的 OrderPayment.created_at 若無付款記錄則為 null
date_completed status === delivered 時為 updated_at 其餘為 null
line_items[] Order.items(含規格與商品) 見下方
coupon_lines[] coupon_code + discount_amount 推導 無折扣碼時為空
refunds[] refunded_amount > 0 時為一筆合成項目 退款端點
meta_data[] 一律包含 _stoar_status_stoar_lookup_token 擴充資料

訂單 line_item

WC 欄位 Stoar 來源
id OrderItem.id
name OrderItem.name
product_id OrderItem.product_id ?? 0
variation_id OrderItem.variant_id ?? 0
quantity OrderItem.quantity
subtotaltotal price * quantity(兩位小數字串)
subtotal_taxtotal_tax OrderItem.tax_amount
sku 優先取規格 SKU,退回商品 SKU
price OrderItem.price

商品

WC 欄位 STOAR 來源 備註
id id
nameslugskudescriptionshort_description 直接沿用
permalink url('/product/' . slug)
type type(已轉換) configurablevariable
status status(已轉換) activepublish
featured is_featured bool
regular_price price(原始值) 兩位小數字串
sale_price special_price(為 null 時是 "" 兩位小數字串
price min(regular, sale) 兩位小數字串
on_sale special_price !== null && special_price < price
purchasable stock > 0 && status === 'active'
manage_stock 恆為 true
stock_quantity stockconfigurable 時為各規格庫存加總
stock_status instockoutofstock
weight weight(字串)
tax_class tax_class_id(字串)
categories[] 來自 category 關聯的單一元素 Stoar 只有單一主分類
images[] image_path + gallery_paths 陣列 第一筆為主圖
variations[] 規格 id(僅限 variable 商品)
meta_data[] 一律包含 _stoar_id_stoar_low_stock_threshold_stoar_image_prompt
attributes[]default_attributes[] [] Stoar 沒有全域屬性系統
tags[]related_ids[]upsell_ids[]cross_sell_ids[] [] Stoar 未建模
dimensions 空值 未追蹤
average_ratingrating_count "0.00"0 此層級未彙總

狀態轉換 #

WooCommerce 與 Stoar 使用不同的狀態詞彙。轉接器會雙向轉換:篩選時(?status=processing)把 WC 值對應到 Stoar;序列化回應時再把 Stoar 的 status 對應回 WC。

訂單狀態

WooCommerce Stoar 備註
pending pending 未付款,等待付款
processing paid (輸出時) /篩選時接受 paid 「款項已請款,出貨處理中」
processing processingshipped (輸出時) Stoar 的 processingshipped 都輸出為 WC 的 processing
completed delivered
cancelled cancelled
refunded refunded
on-hold pending (僅限篩選) Stoar 沒有明確的 on-hold 狀態
failed cancelled (僅限篩選) 最接近的對應;Stoar 沒有明確的 failed 狀態

商品狀態

WooCommerce Stoar
publish active
draftpendingprivate inactive

商品類型

WooCommerce Stoar
simple simple
variable configurable
groupedexternal (不支援——Stoar 沒有)

對應到 null 的篩選值(例如對商品下 ?status=trash)會被靜默忽略——不會回報錯誤。


回應結構 #

訂單——附註解範例

{
  "id":             456,
  "parent_id":      0,
  "number":         "456",
  "order_key":      "abc123…",
  "created_via":    "checkout",
  "version":        "8.5.0",
  "status":         "processing",
  "currency":       "EUR",
  "date_created":   "2026-04-10T09:00:00+00:00",
  "date_modified":  "2026-04-10T09:30:00+00:00",
  "discount_total": "0.00",
  "discount_tax":   "0.00",
  "shipping_total": "5.00",
  "shipping_tax":   "0.00",
  "cart_tax":       "10.00",
  "total":          "115.00",
  "total_tax":      "10.00",
  "prices_include_tax": false,
  "customer_id":    45,
  "customer_note":  "",
  "billing":        { /* WC address shape (flat) */ },
  "shipping":       { /* WC address shape (flat) */ },
  "payment_method": "stripe",
  "payment_method_title": "Credit / Debit Card",
  "transaction_id": "pi_test_…",
  "date_paid":      "2026-04-10T09:05:00+00:00",
  "date_completed": null,
  "cart_hash":      "",
  "meta_data":      [
    { "id": 0, "key": "_stoar_status",       "value": "paid" },
    { "id": 0, "key": "_stoar_lookup_token", "value": "abc123…" }
  ],
  "line_items": [
    {
      "id":            456,
      "name":          "Widget",
      "product_id":    789,
      "variation_id":  12,
      "quantity":      2,
      "tax_class":     "",
      "subtotal":      "100.00",
      "subtotal_tax":  "10.00",
      "total":         "100.00",
      "total_tax":     "10.00",
      "taxes":         [],
      "meta_data":     [],
      "sku":           "WID-1-A",
      "price":         50
    }
  ],
  "tax_lines":      [],
  "shipping_lines": [
    {
      "id":           0,
      "method_title": "Standard",
      "method_id":    "flat_rate",
      "instance_id":  "",
      "total":        "5.00",
      "total_tax":    "0.00",
      "taxes":        [],
      "meta_data":    []
    }
  ],
  "fee_lines":    [],
  "coupon_lines": [],
  "refunds":      [],
  "_links":       {
    "self":       [{ "href": "https://app.stoar.ai/wp-json/wc/v3/orders/456" }],
    "collection": [{ "href": "https://app.stoar.ai/wp-json/wc/v3/orders" }]
  }
}

商品——節錄範例

{
  "id":                 789,
  "name":               "Widget",
  "slug":               "widget",
  "permalink":          "https://app.stoar.ai/product/widget",
  "type":               "simple",
  "status":             "publish",
  "featured":           true,
  "catalog_visibility": "visible",
  "description":        "<p>A great widget</p>",
  "short_description":  "Great widget",
  "sku":                "WID-1",
  "price":              "79.99",
  "regular_price":      "99.99",
  "sale_price":         "79.99",
  "on_sale":            true,
  "purchasable":        true,
  "manage_stock":       true,
  "stock_quantity":     42,
  "stock_status":       "instock",
  "weight":             "1.5",
  "categories":         [{ "id": 5, "name": "Widgets", "slug": "widgets" }],
  "images":             [
    { "id": 0, "src": "products/widget.webp", "name": "primary",   "position": 0, "alt": "" },
    { "id": 0, "src": "products/g1.webp",     "name": "gallery-1", "position": 1, "alt": "" }
  ],
  "attributes":         [],
  "variations":         [],
  "meta_data":          [
    { "id": 0, "key": "_stoar_id", "value": "789" },
    { "id": 0, "key": "_stoar_low_stock_threshold", "value": "3" }
  ],
  "_links":             {
    "self":       [{ "href": "https://app.stoar.ai/wp-json/wc/v3/products/789" }],
    "collection": [{ "href": "https://app.stoar.ai/wp-json/wc/v3/products" }]
  }
}

對於可組態/variable 商品,variations 會填入規格 id,stock_quantity 則是各規格庫存的加總。


實際範例 #

正式環境對 GET /wp-json/wc/v3/orders/10126 的即時回應(USD $936.98,兩個簡單商品明細,以 PayID 付款)。個資已匿名化。

請求

GET /wp-json/wc/v3/orders/10126
Authorization: Bearer 2|L5pXj63e881lkgtHPK7Hjozyq7Pb3trHCy0iaDRf76405f72

回應

{
  "id":               10126,
  "parent_id":        0,
  "number":           "10126",
  "order_key":        "REDACTED-FOR-DOCS",
  "created_via":      "checkout",
  "version":          "8.5.0",
  "status":           "processing",
  "currency":         "USD",
  "date_created":     "2025-06-03T04:56:43+00:00",
  "date_modified":    "2025-06-03T04:56:43+00:00",
  "discount_total":   "0.00",
  "discount_tax":     "0.00",
  "shipping_total":   "0.00",
  "shipping_tax":     "0.00",
  "cart_tax":         "0.00",
  "total":            "936.98",
  "total_tax":        "0.00",
  "prices_include_tax": false,
  "customer_id":      5794,
  "customer_note":    "",
  "billing": {
    "first_name": "Jane",
    "last_name":  "Doe",
    "company":    "",
    "address_1":  "1 Example Street",
    "address_2":  "",
    "city":       "Phoenix",
    "state":      "AZ",
    "postcode":   "85001",
    "country":    "US",
    "email":      "",
    "phone":      "+1-555-0100"
  },
  "shipping":         { /* same shape as billing */ },
  "payment_method":   "payid",
  "payment_method_title": "PayID",
  "transaction_id":   "",
  "date_paid":        null,
  "date_completed":   null,
  "cart_hash":        "",
  "meta_data": [
    { "id": 0, "key": "_stoar_status",       "value": "paid" },
    { "id": 0, "key": "_stoar_lookup_token", "value": "REDACTED-FOR-DOCS" }
  ],
  "line_items": [
    {
      "id":           30219,
      "name":         "Reloop Terminal Mix 8",
      "product_id":   112238,
      "variation_id": 95589,
      "quantity":     3,
      "tax_class":    "",
      "subtotal":     "897.00",
      "subtotal_tax": "0.00",
      "total":        "897.00",
      "total_tax":    "0.00",
      "taxes":        [],
      "meta_data":    [],
      "sku":          "RELOOP_TERMINALMIX8_025-DEF",
      "price":        299
    },
    {
      "id":           30220,
      "name":         "Premium Skateboard Socks",
      "product_id":   51706,
      "variation_id": 33857,
      "quantity":     2,
      "tax_class":    "",
      "subtotal":     "39.98",
      "subtotal_tax": "0.00",
      "total":        "39.98",
      "total_tax":    "0.00",
      "taxes":        [],
      "meta_data":    [],
      "sku":          "SK8-SOCK-027-DEF",
      "price":        19.99
    }
  ],
  "tax_lines":      [],
  "shipping_lines": [
    {
      "id":           0,
      "method_title": "Free Shipping",
      "method_id":    "flat_rate",
      "instance_id":  "",
      "total":        "0.00",
      "total_tax":    "0.00",
      "taxes":        [],
      "meta_data":    []
    }
  ],
  "fee_lines":    [],
  "coupon_lines": [],
  "refunds":      [],
  "_links":       {
    "self":       [{ "href": "https://app.stoar.ai/wp-json/wc/v3/orders/10126" }],
    "collection": [{ "href": "https://app.stoar.ai/wp-json/wc/v3/orders" }]
  }
}

整合者應注意的細節

這些與 Magento 的注意事項重疊——底層的 Stoar 資料是同一份,只是以不同的外層結構呈現:

欄位 實際觀察 原因
transaction_iddate_paid 已付款訂單為 ""null 取自 Stoar 的 OrderPayment 稽核記錄;早於該記錄的舊訂單會顯示為空
payment_method "payid" 這是 STOAR 的金流商鍵值(stripebank_transfercash_on_deliverypayidinvoice)——並非 WC 標準的方式名稱
payment_method_title 由金流商鍵值推導 寫死的對應表——如需擴充請修改 OrderResource::paymentMethodTitle()
version 恆為 "8.5.0" 寫死——並非實際執行中的 WC 版本
created_via 恆為 "checkout" Stoar 目前還沒有以 API 建立訂單的流程
customer_ip_addresscustomer_user_agent 恆為 "" 未儲存在 Order 上
cart_hash 恆為 "" 未儲存
tax_lines 恆為 [] Stoar 只在訂單層級追蹤稅額,不分稅務轄區
attributesdefault_attributes(商品) 恆為 [] Stoar 沒有全域屬性分類體系
meta_data._stoar_lookup_token 每筆訂單的魔法連結 token 與 Magento 相同的安全警告——只要持有它就能在未驗證的情況下檢視訂單。切勿將其暴露在用戶端程式碼或記錄中。

錯誤結構 #

WooCommerce 的錯誤格式為:

{
  "code":    "machine_readable_code",
  "message": "Human-readable message",
  "data":    { "status": 404, "id": 99999 }
}

……而非 Magento 的 {message, parameters, trace}

HTTP 觸發原因 code
400 查詢參數錯誤/缺少必要內文 rest_invalid_param
401 缺少或無效的 token woocommerce_rest_cannot_view
403 token 能力不符(例如只有 magento:admin 的 token,或顧客 token) woocommerce_rest_authorization_required
404 未知的資源 id woocommerce_rest_shop_order_invalid_idwoocommerce_rest_product_invalid_id
422 前置條件不符(對不可退款的訂單退款等) woocommerce_rest_invalid_state
429 超出流量限制 woocommerce_rest_too_many_requests
500 非預期的伺服器錯誤 woocommerce_rest_internal_error

data.status 永遠與 HTTP 狀態碼一致。有意義時會加上資源專屬的鍵(data.id)。


流量限制 #

保護 Magento 的同一組以 Sanctum token 為鍵的節流機制(api-rest,預設每分鐘 60 次請求)同樣保護 WC 路由。兩者都可在 /manager/api-settings 全域設定。觸發時,回應會使用 WC 的錯誤外層結構:

{
  "code":    "woocommerce_rest_too_many_requests",
  "message": "Too many requests. Please retry after a short pause.",
  "data":    { "status": 429 }
}

設定介面的完整操作說明請見 Magento 文件的「流量限制」一節。


延伸閱讀 #

  • app/Api/Core/OrderRepository.phpapp/Api/Core/ProductRepository.php——每個轉接器都倚賴的抽象邊界
  • app/Api/Adapters/WooCommerce/Support/StatusTranslator.php——雙向詞彙對應
  • WooCommerce REST API 參考文件——本轉接器所對應的上游規格