首頁/接入第三方充值 / 發卡 API
開發文件

接入第三方充值 / 發卡 API

最近更新:2026-10-08

一句話總結

預設走內建 Mock 供應商。接真實上游:填環境變數,重啟,不改程式碼。

1. 上游只需要提供五種能力

能力對應方法用途
拉目錄pullCatalog()同步價格、庫存、缺貨狀態
查庫存fetchStock(ids)下單前校驗
下單createOrder(req)帶冪等鍵,同步回傳或非同步發貨
查單queryOrder(id)Webhook 之外的兜底輪詢
回調verifyWebhook()非同步交付結果的主路徑

2. 環境變數

UPSTREAM_ENABLED=true
UPSTREAM_ADAPTER=rest
UPSTREAM_BASE_URL=https://api.supplier.example
UPSTREAM_API_KEY=xxxxxxxx
UPSTREAM_API_SECRET=yyyyyyyy
UPSTREAM_SIGNATURE=hmac_sha256   # none|bearer|header_key|query_key|hmac_sha256|md5

UPSTREAM_PATH_CATALOG=/api/products
UPSTREAM_PATH_CREATE_ORDER=/api/order/create
UPSTREAM_PATH_QUERY_ORDER=/api/order/query

UPSTREAM_MAPPING_JSON='{"itemsPath":"data.list","fields":{"externalId":"id","title":"name","price":"price","stock":"stock","soldOutFlag":"sold_out"},"order":{"orderIdPath":"data.order_no","contentPath":"data.content"}}'

3. 簽章做了什麼

hmac_sha256 策略:把請求體按參數名排序拼成 k1=v1&k2=v2,尾部拼上 API Secret 再取摘要。這是國內絕大多數平台的通行做法,md5 是老平台的變體。

Webhook 驗簽採用 constant-time 比較,並校驗時間戳容忍視窗,防止重送。

4. 欄位對應怎麼填

  • itemsPath:回應裡陣列所在的路徑,例如 data.list。
  • fields.externalId:商品唯一標識,會與站內商品的 upstream_ref 對齊。
  • soldOutFlag / soldOutWhen:不同平台表達缺貨的方式五花八門(布林、字串、庫存為 0),用這兩個欄位統一。
  • order.contentPath:交付內容所在路徑,字串按行拆成多條憑證,陣列按元素拆。

5. 換一家有多快

如果新平台的介面形態仍在這五個能力內:只改環境變數,程式碼零改動。

如果它比較另類(例如 SOAP、私有二進位協定、需要登入態會話):新增一個實作 UpstreamAdapter 的檔案,在工廠裡註冊,其餘層完全無感。

6. 自我檢查

GET /api/upstream/health

回傳目前生效的設定摘要、健康狀態、目錄條數。接新供應商後先看這個介面。

7. 穩定性策略

  • 逾時 + 退避重試:預設 10s 逾時,最多重試 2 次。
  • 下單不激進重試:避免重複發貨,只重試 1 次。
  • 目錄快取:預設 60s。上游抖動時回傳上一次結果並標記 stale,頁面不白屏。
  • 冪等鍵:訂單號-行號,同一筆重複提交只產生一個上游單。

8. 程式碼位置

lib/server/upstream/types.ts         # 介面契約(五種能力)
lib/server/upstream/mock-adapter.ts  # 本地供應商
lib/server/upstream/rest-adapter.ts  # 通用 REST 適配器
lib/server/upstream/index.ts         # 門面:快取、降級、錯誤處理
lib/server/env.ts                    # 全部設定項
lib/server/http.ts                   # 逾時/重試/冪等
lib/server/signature.ts              # 簽章與 Webhook 驗簽
app/api/upstream/health/route.ts     # 自我檢查介面
app/api/upstream/webhook/route.ts    # 非同步回調入口