Skip to content

User 前臺 API 文檔 ​

更新時間:2026-03-31

本文檔覆蓋 user/src/api/index.ts 當前全部前臺 API,字段定義以以下實現為準:

  • api/internal/router/router.go
  • api/internal/http/handlers/public/*.go
  • api/internal/models/*.go

開源倉庫地址 ​


0. API 變更日誌 ​

0.0.1 Public API Response DTO 精簡與安全加固(2026-03-31) ​

破壞性變更 ​

  • 所有訂單相關介面不再返回自增 id 字段(Order.id、OrderItem.id、Fulfillment.id),統一使用 order_no 作為訂單標識。
  • 訂單詳情路由從 GET /orders/:id 改為 GET /orders/:order_no;取消路由從 POST /orders/:id/cancel 改為 POST /orders/:order_no/cancel;交付下載從 GET /orders/:id/fulfillment/download 改為 GET /orders/:order_no/fulfillment/download。
  • 遊客訂單詳情路由從 GET /guest/orders/:id 改為 GET /guest/orders/:order_no;交付下載同理。
  • 舊路由 GET /orders/by-order-no/:order_no 和 GET /guest/orders/by-order-no/:order_no 已刪除,直接使用 GET /orders/:order_no。
  • 支付介面 POST /payments 和 GET /payments/latest 的請求參數 order_id 改為 order_no(string 類型)。遊客支付介面同理。
  • GET /payments/latest 響應中 order_id 改為 order_no。

移除的字段 ​

以下字段從 Public API 響應中永久移除,前端不應再依賴:

  • Order: id、parent_id、user_id、coupon_id、promotion_id、client_ip、updated_at
  • OrderItem: id、order_id、delivered_by、created_at、updated_at
  • Fulfillment: id、order_id、delivered_by、created_at、updated_at
  • PublicProduct: cost_price_amount、manual_stock_locked、manual_stock_sold、is_active、sort_order、created_at、updated_at、is_affiliate_enabled、is_mapped、seo_meta
  • PublicSKU: cost_price_amount、product_id、manual_stock_locked、auto_stock_total、auto_stock_locked、auto_stock_sold、sort_order、created_at、updated_at
  • Banner: name、is_active、start_at、end_at、sort_order、created_at、updated_at
  • Post: is_published、created_at
  • Category: created_at
  • WalletTransaction: order_id
  • AffiliateCommission: order_id

新增的字段 ​

  • Order: member_discount_amount、wallet_paid_amount、online_paid_amount、refunded_amount
  • OrderItem: sku_snapshot、member_discount_amount
  • Fulfillment: payload_line_count
  • UserProfile: member_level_id、total_recharged、total_spent
  • Category: parent_id、icon

0.0 活動價系統改進:階梯規則 + 前端展示優化(2026-03-09) ​

新增字段 ​

  • PublicProduct 新增 promotion_rules 字段(類型 PromotionRule[]),返回該商品所有生效中的活動規則。
  • 即使當前 SKU 單價未滿足活動門檻,該字段也會返回資料,便於前端展示「多買可享折扣」等活動提示。

階梯活動規則 ​

  • 同一商品支援配置多條活動規則(不同 min_amount 門檻),形成階梯折扣。
  • 後端按購買小計(單價 × 數量)從高到低匹配門檻,取滿足條件的最高檔規則計算折扣。
  • 範例:
    • 規則 A:min_amount=50,優惠 1%
    • 規則 B:min_amount=150,優惠 2%
    • 購買金額 49 → 無折扣;100 → 匹配規則 A(1%);200 → 匹配規則 B(2%)
  • 單條規則場景行為不變,無破壞性變更。

活動類型說明 ​

type含義計算方式
percent百分比折扣每件單價 = 原價 × (100 - value) / 100
fixed固定金額減免每件單價 = 原價 - value
special_price直降特價每件單價 = value

注意: 所有折扣均作用於單件商品價格,而非訂單總金額。min_amount 是購買小計門檻(單價 × 數量),達到門檻後每件商品享受對應折扣。


1. 通用約定 ​

1.1 Base URL ​

  • API 前綴:/api/v1
  • 本文中的路徑均省略 /api/v1,調用時請自行拼接。

1.2 鑑權 ​

用戶登錄態介面需攜帶:

http
Authorization: Bearer <user_token>

1.3 統一響應結構 ​

成功響應 ​

json
{
  "status_code": 0,
  "msg": "success",
  "data": {},
  "pagination": {
    "page": 1,
    "page_size": 20,
    "total": 100,
    "total_page": 5
  }
}

失敗響應 ​

json
{
  "status_code": 400,
  "msg": "請求參數錯誤",
  "data": {
    "request_id": "01HR..."
  }
}

頂層字段說明 ​

字段類型說明
status_codenumber業務狀態碼,0 表示成功,非 0 表示失敗
msgstring業務提示信息
dataobject/array/null業務數據
paginationobject分頁信息,僅分頁介面返回

1.4 分頁參數約定 ​

參數類型必填默認說明
pagenumber否1頁碼,最小 1
page_sizenumber否20每頁條數,最大 100

1.5 通用請求結構 ​

CaptchaPayload(驗證碼載荷) ​

字段類型必填說明
captcha_idstring否圖片驗證碼 ID(provider=image 時使用)
captcha_codestring否圖片驗證碼文本(provider=image 時使用)
turnstile_tokenstring否Turnstile Token(provider=turnstile 時使用)

OrderItemInput(訂單項) ​

字段類型必填說明
product_idnumber是商品 ID
quantitynumber是購買數量(>0)
fulfillment_typestring否交付類型,推薦值:manual / auto

ManualFormData(人工交付表單值) ​

manual_form_data 是對象,Key 為 product_id,Value 為該商品的表單提交數據。

json
{
  "1001": {
    "receiver_name": "張三",
    "phone": "13277745648",
    "address": "廣東省深圳市..."
  }
}

2. 數據對象字段字典 ​

以下對象用於後續各介面「返回結構」引用。

2.1 PublicProduct ​

字段類型說明
category_idnumber分類 ID
slugstring商品唯一標識
titleobject多語言標題
descriptionobject多語言摘要
contentobject多語言詳情內容
price_amountstring商品價格金額
imagesstring[]商品圖片列表
tagsstring[]標籤列表
purchase_typestring購買身份限制:guest / member
min_purchase_quantitynumber單次最小購買數量(0 表示不限)
max_purchase_quantitynumber單次最大購買數量(0 表示不限)
fulfillment_typestring交付類型:manual / auto
manual_form_schemaobject人工交付表單 Schema
manual_stock_availablenumber人工可用庫存
auto_stock_availablenumber自動可用庫存
stock_statusstring庫存狀態:unlimited / in_stock / low_stock / out_of_stock
is_sold_outboolean是否售罄
categoryCategory分類信息
skusPublicSKU[]SKU 列表
promotion_idnumber命中的活動 ID(可選)
promotion_namestring活動名稱(可選)
promotion_typestring活動類型(可選)
promotion_price_amountstring活動價金額(可選)
promotion_rulesPromotionRule[]活動規則列表(可選)
member_pricesMemberLevelPrice[]會員等級價格列表(可選)

2.1.1 PublicSKU ​

skus[] 陣列中每個元素的結構如下:

字段類型說明
idnumberSKU ID(下單時使用此 ID)
sku_codestringSKU 編碼(同商品內唯一)
spec_valuesobject規格值(多語言)
price_amountstringSKU 原價
manual_stock_totalnumber人工庫存總量(-1 表示無限庫存)
manual_stock_soldnumber人工庫存已售量
auto_stock_availablenumber自動發貨庫存可用量
upstream_stocknumber上游庫存(-1 表示無限,0 表示售罄)
is_activeboolean是否啟用
promotion_price_amountstringSKU 活動價金額(可選)
member_price_amountstring會員價金額(可選)

2.1.2 PromotionRule ​

promotion_rules[] 陣列中每個元素的結構如下:

字段類型說明
idnumber活動規則 ID
namestring活動名稱
typestring活動類型:percent / fixed / special_price
valuestring活動數值(字串金額/百分比,如 "2.00" 或 "5.00")
min_amountstring觸發門檻金額(購買小計 = 單價 × 數量,如 "200.00";"0.00" 表示無門檻)

活動類型與折扣計算:

type含義折扣計算(作用於每件單價)
percent百分比折扣單價 = 原價 × (100 - value) / 100
fixed固定金額減免單價 = 原價 - value
special_price直降特價單價 = value
  • 所有折扣均作用於單件商品價格,而非訂單總金額。
  • min_amount 是購買小計門檻(單價 × 數量),達到門檻後每件商品享受對應折扣。
  • 同一商品可配置多條不同 min_amount 的規則,形成階梯折扣。後端從高到低匹配,取滿足條件的最高檔。

促銷價計算說明: 促銷活動以商品為維度配置,促銷價下沉到每個 SKU 獨立計算。例如某商品配置了「優惠 2%」促銷,99 元的 SKU 促銷價為 97.02,77 元的 SKU 促銷價為 75.46。產品級的 promotion_price_amount 取所有 SKU 中的最低促銷價,適用於列表頁展示。promotion_rules 返回所有生效規則(按 min_amount 升序),即使當前單價未滿足門檻也會返回,便於前端展示活動提示。

2.2 Post ​

字段類型說明
idnumber文章 ID
slugstring文章唯一標識
typestring類型:blog / notice
titleobject多語言標題
summaryobject多語言摘要
contentobject多語言內容
thumbnailstring縮略圖 URL
published_atstring/null發佈時間

2.3 Banner ​

字段類型說明
idnumberBanner ID
positionstring投放位置(如 home_hero)
titleobject多語言標題
subtitleobject多語言副標題
imagestring主圖
mobile_imagestring移動端圖
link_typestring跳轉類型:none / internal / external
link_valuestring跳轉值
open_in_new_tabboolean是否新窗口打開

2.4 Category ​

字段類型說明
idnumber分類 ID
parent_idnumber父分類 ID(0 表示一級分類)
slugstring分類唯一標識
nameobject多語言名稱
iconstring分類圖標
sort_ordernumber排序

2.5 UserProfile ​

字段類型說明
idnumber用戶 ID
emailstring郵箱
nicknamestring暱稱
email_verified_atstring/null郵箱驗證時間
localestring語言(如 zh-CN)
member_level_idnumber會員等級 ID
total_rechargedstring累計充值金額
total_spentstring累計消費金額
email_change_modestring郵箱變更模式:bind_only / change_with_old_and_new
password_change_modestring密碼變更模式:set_without_old / change_with_old

2.6 UserLoginLog ​

字段類型說明
idnumber日誌 ID
user_idnumber用戶 ID(失敗時可能為 0)
emailstring登錄郵箱
statusstring登錄結果:success / failed
fail_reasonstring失敗原因枚舉
client_ipstring客戶端 IP
user_agentstring客戶端 UA
login_sourcestring登錄來源:web / telegram
request_idstring請求追蹤 ID
created_atstring記錄創建時間

2.7 OrderPreview ​

字段類型說明
currencystring幣種(全站統一,來源 site_config.currency)
original_amountstring原價總額
discount_amountstring總優惠金額
promotion_discount_amountstring活動優惠金額
total_amountstring應付總額
itemsOrderPreviewItem[]預覽訂單項

2.8 OrderPreviewItem ​

字段類型說明
product_idnumber商品 ID
titleobject商品標題快照(多語言)
tagsstring[]商品標籤快照
unit_pricestring單價
quantitynumber數量
total_pricestring小計
coupon_discount_amountstring優惠券分攤金額
promotion_discount_amountstring活動分攤金額
fulfillment_typestring交付類型

2.9 Order ​

字段類型說明
order_nostring訂單號
guest_emailstring遊客郵箱(遊客訂單)
guest_localestring遊客語言
statusstring訂單狀態:pending_payment / paid / fulfilling / partially_delivered / delivered / completed / canceled
currencystring訂單幣種
original_amountstring原價
discount_amountstring優惠金額
member_discount_amountstring會員優惠金額
promotion_discount_amountstring活動優惠金額
total_amountstring實付金額
wallet_paid_amountstring錢包支付金額
online_paid_amountstring線上支付金額
refunded_amountstring已退款金額
expires_atstring/null待支付過期時間
paid_atstring/null支付成功時間
canceled_atstring/null取消時間
created_atstring創建時間
itemsOrderItem[]訂單項
fulfillmentFulfillment交付記錄(可選)
childrenOrder[]子訂單列表(可選)

2.10 OrderItem ​

字段類型說明
titleobject商品標題快照
sku_snapshotobjectSKU 快照(編碼/規格)
tagsstring[]商品標籤快照
unit_pricestring單價
quantitynumber數量
total_pricestring小計
coupon_discount_amountstring優惠券分攤金額
member_discount_amountstring會員優惠分攤金額
promotion_discount_amountstring活動優惠金額
fulfillment_typestring交付類型
manual_form_schema_snapshotobject人工交付表單 Schema 快照
manual_form_submissionobject用戶提交的人工表單值

2.11 Fulfillment ​

字段類型說明
typestring交付類型:auto / manual
statusstring交付狀態:pending / delivered
payloadstring文本交付內容
payload_line_countnumber交付內容總行數
delivery_dataobject結構化交付信息
delivered_atstring/null交付時間

2.12 PaymentLaunch ​

字段類型說明
payment_idnumber支付記錄 ID
order_nostring訂單號(latest 介面返回)
channel_idnumber支付渠道 ID(latest 介面返回)
provider_typestring提供方:official / epay
channel_typestring渠道:alipay / wechat / paypal / stripe 等
interaction_modestring交互方式:qr / redirect / wap / page
pay_urlstring跳轉支付連結
qr_codestring二維碼內容
expires_atstring/null支付單過期時間

3. 公共介面(無需登錄) ​

3.1 獲取站點配置 ​

介面:GET /public/config

認證:否

請求參數 ​

無

成功響應示例 ​

json
{
  "status_code": 0,
  "msg": "success",
  "data": {
    "languages": ["zh-CN", "zh-TW", "en-US"],
    "currency": "CNY",
    "contact": {
      "telegram": "https://telegram.me/dujiaostudio",
      "whatsapp": "https://wa.me/1234567890"
    },
    "site_name": "Dujiao-Next",
    "scripts": [
      {
        "name": "Plausible",
        "enabled": true,
        "position": "head",
        "code": "<script defer data-domain=\"localhost\" src=\"https://xxx.com/js/script.js\"></script>"
      }
    ],
    "payment_channels": [
      {
        "id": 1,
        "name": "支付寶電腦站",
        "provider_type": "official",
        "channel_type": "alipay",
        "interaction_mode": "page",
        "fee_rate": "0.00"
      }
    ],
    "captcha": {
      "provider": "turnstile",
      "scenes": {
        "login": true,
        "register_send_code": true,
        "reset_send_code": false,
        "guest_create_order": false
      },
      "turnstile": {
        "site_key": "0x4AAA..."
      }
    },
    "telegram_auth": {
      "enabled": true,
      "bot_username": "dujiao_auth_bot"
    },
    "google_auth": {
      "enabled": true,
      "client_id": "1234567890-xxxx.apps.googleusercontent.com"
    }
  }
}

返回結構(data) ​

字段類型說明
languagesstring[]站點啟用語言列表
currencystring全站幣種(3 位大寫代碼,如 CNY)
contactobject聯繫方式配置
scriptsobject[]前臺自訂 JS 腳本配置
payment_channelsobject[]前臺可用支付渠道列表
captchaobject驗證碼公開配置
telegram_authobjectTelegram 登錄公開配置(enabled、bot_username)
google_authobjectGoogle 登入公開配置(enabled、client_id)
其他字段any後臺站點設置中的公開字段(動態擴展)

3.2 商品列表 ​

介面:GET /public/products

認證:否

Query 參數 ​

參數類型必填說明
pagenumber否頁碼
page_sizenumber否每頁條數(最大 100)
category_idstring否分類 ID
searchstring否搜索關鍵詞(標題等)

成功響應示例 ​

json
{
  "status_code": 0,
  "msg": "success",
  "data": [
    {
      "category_id": 10,
      "slug": "netflix-plus",
      "title": { "zh-CN": "奈飛會員" },
      "description": { "zh-CN": "全區可用" },
      "content": { "zh-CN": "詳情說明" },
      "price_amount": "99.00",
      "images": ["/uploads/product/1.png"],
      "tags": ["熱門"],
      "purchase_type": "member",
      "fulfillment_type": "manual",
      "manual_form_schema": { "fields": [] },
      "manual_stock_available": 88,
      "auto_stock_available": 0,
      "stock_status": "in_stock",
      "is_sold_out": false
    }
  ],
  "pagination": {
    "page": 1,
    "page_size": 20,
    "total": 1,
    "total_page": 1
  }
}

返回結構(data) ​

  • data:PublicProduct[]
  • pagination:分頁對象(見通用約定)

3.3 商品詳情 ​

介面:GET /public/products/:slug

認證:否

Path 參數 ​

參數類型必填說明
slugstring是商品 slug

成功響應示例 ​

json
{
  "status_code": 0,
  "msg": "success",
  "data": {
    "slug": "netflix-plus",
    "title": { "zh-CN": "奈飛會員" },
    "price_amount": "99.00",
    "fulfillment_type": "manual",
    "manual_form_schema": {
      "fields": [
        {
          "key": "receiver_name",
          "type": "text",
          "required": true,
          "label": { "zh-CN": "收件人" }
        }
      ]
    },
    "manual_stock_available": 88,
    "auto_stock_available": 0,
    "stock_status": "in_stock",
    "is_sold_out": false
  }
}

返回結構(data) ​

  • data:PublicProduct

3.4 文章列表 ​

介面:GET /public/posts

認證:否

Query 參數 ​

參數類型必填說明
pagenumber否頁碼
page_sizenumber否每頁條數
typestring否文章類型:blog / notice

成功響應示例 ​

json
{
  "status_code": 0,
  "msg": "success",
  "data": [
    {
      "id": 1,
      "slug": "release-2026-02",
      "type": "notice",
      "title": { "zh-CN": "版本更新" },
      "summary": { "zh-CN": "新增支付渠道" },
      "content": { "zh-CN": "詳細內容" },
      "thumbnail": "/uploads/post/1.png",
      "published_at": "2026-02-11T10:00:00Z"
    }
  ],
  "pagination": {
    "page": 1,
    "page_size": 20,
    "total": 1,
    "total_page": 1
  }
}

返回結構(data) ​

  • data:Post[]
  • pagination:分頁對象

3.5 文章詳情 ​

介面:GET /public/posts/:slug

認證:否

Path 參數 ​

參數類型必填說明
slugstring是文章 slug

成功響應示例 ​

json
{
  "status_code": 0,
  "msg": "success",
  "data": {
    "id": 1,
    "slug": "release-2026-02",
    "type": "notice",
    "title": { "zh-CN": "版本更新" },
    "summary": { "zh-CN": "新增支付渠道" },
    "content": { "zh-CN": "詳細內容" },
    "thumbnail": "/uploads/post/1.png",
    "published_at": "2026-02-11T10:00:00Z"
  }
}

返回結構(data) ​

  • data:Post

3.6 Banner 列表 ​

介面:GET /public/banners

認證:否

Query 參數 ​

參數類型必填默認說明
positionstring否home_heroBanner 位置
limitnumber否10最大 50

成功響應示例 ​

json
{
  "status_code": 0,
  "msg": "success",
  "data": [
    {
      "id": 1,
      "position": "home_hero",
      "title": { "zh-CN": "歡迎來到 D&N" },
      "subtitle": { "zh-CN": "穩定交付" },
      "image": "/uploads/banner/hero.png",
      "mobile_image": "/uploads/banner/hero-mobile.png",
      "link_type": "internal",
      "link_value": "/products",
      "open_in_new_tab": false
    }
  ]
}

返回結構(data) ​

  • data:Banner[]

3.7 分類列表 ​

介面:GET /public/categories

認證:否

請求參數 ​

無

成功響應示例 ​

json
{
  "status_code": 0,
  "msg": "success",
  "data": [
    {
      "id": 10,
      "parent_id": 0,
      "slug": "memberships",
      "name": { "zh-CN": "會員服務" },
      "icon": "",
      "sort_order": 100
    }
  ]
}

返回結構(data) ​

  • data:Category[]

3.8 獲取圖片驗證碼挑戰 ​

介面:GET /public/captcha/image

認證:否

請求參數 ​

無

成功響應示例 ​

json
{
  "status_code": 0,
  "msg": "success",
  "data": {
    "captcha_id": "9f2b2be147df4f6eb6f8",
    "image_base64": "data:image/png;base64,iVBORw0KGgoAAA..."
  }
}

返回結構(data) ​

字段類型說明
captcha_idstring本次驗證碼 ID
image_base64stringBase64 圖片(data URL)

4. 認證介面(無需登錄) ​

4.1 發送郵箱驗證碼 ​

介面:POST /auth/send-verify-code

認證:否

Body 參數 ​

字段類型必填說明
emailstring是郵箱
purposestring是驗證碼用途:register / reset
captcha_payloadobject否驗證碼參數(見通用結構)

請求示例 ​

json
{
  "email": "[email protected]",
  "purpose": "register",
  "captcha_payload": {
    "captcha_id": "",
    "captcha_code": "",
    "turnstile_token": ""
  }
}

成功響應示例 ​

json
{
  "status_code": 0,
  "msg": "success",
  "data": {
    "sent": true
  }
}

返回結構(data) ​

字段類型說明
sentboolean是否發送成功

4.2 用戶註冊 ​

介面:POST /auth/register

認證:否

Body 參數 ​

字段類型必填說明
emailstring是郵箱
passwordstring是密碼
codestring是郵箱驗證碼
agreement_acceptedboolean是是否同意協議,必須為 true

請求示例 ​

json
{
  "email": "[email protected]",
  "password": "StrongPass123",
  "code": "123456",
  "agreement_accepted": true
}

成功響應示例 ​

json
{
  "status_code": 0,
  "msg": "success",
  "data": {
    "user": {
      "id": 101,
      "email": "[email protected]",
      "nickname": "user",
      "email_verified_at": "2026-02-11T10:00:00Z"
    },
    "token": "eyJhbGciOi...",
    "expires_at": "2026-02-18T10:00:00Z"
  }
}

返回結構(data) ​

字段類型說明
userobject註冊用戶信息(id/email/nickname/email_verified_at)
tokenstring用戶 JWT
expires_atstringToken 過期時間(RFC3339)

4.3 用戶登錄 ​

介面:POST /auth/login

認證:否

Body 參數 ​

字段類型必填說明
emailstring是郵箱
passwordstring是密碼
remember_meboolean否是否延長登錄態
captcha_payloadobject否驗證碼參數(見通用結構)

請求示例 ​

json
{
  "email": "[email protected]",
  "password": "StrongPass123",
  "remember_me": true,
  "captcha_payload": {
    "captcha_id": "",
    "captcha_code": "",
    "turnstile_token": ""
  }
}

成功響應示例 ​

json
{
  "status_code": 0,
  "msg": "success",
  "data": {
    "user": {
      "id": 101,
      "email": "[email protected]",
      "nickname": "user",
      "email_verified_at": "2026-02-11T10:00:00Z"
    },
    "token": "eyJhbGciOi...",
    "expires_at": "2026-02-25T10:00:00Z"
  }
}

返回結構(data) ​

與註冊介面一致:user + token + expires_at


4.4 忘記密碼 ​

介面:POST /auth/forgot-password

認證:否

Body 參數 ​

字段類型必填說明
emailstring是郵箱
codestring是郵箱驗證碼
new_passwordstring是新密碼

請求示例 ​

json
{
  "email": "[email protected]",
  "code": "123456",
  "new_password": "NewStrongPass123"
}

成功響應示例 ​

json
{
  "status_code": 0,
  "msg": "success",
  "data": {
    "reset": true
  }
}

返回結構(data) ​

字段類型說明
resetboolean是否重置成功

4.5 Telegram 登錄 ​

介面:POST /auth/telegram/login

認證:否

Body 參數 ​

字段類型必填說明
idnumber是Telegram 用戶 ID
first_namestring否名
last_namestring否姓
usernamestring否Telegram 用戶名
photo_urlstring否Telegram 頭像 URL
auth_datenumber是Telegram 授權時間戳(秒)
hashstring是Telegram 登錄簽名

請求示例 ​

json
{
  "id": 123456789,
  "first_name": "Dujiao",
  "last_name": "User",
  "username": "dujiao_user",
  "photo_url": "https://t.me/i/userpic/320/xxx.jpg",
  "auth_date": 1739250000,
  "hash": "f1b2c3..."
}

成功響應示例 ​

json
{
  "status_code": 0,
  "msg": "success",
  "data": {
    "user": {
      "id": 101,
      "email": "[email protected]",
      "nickname": "telegram_123456789",
      "email_verified_at": null
    },
    "token": "eyJhbGciOi...",
    "expires_at": "2026-02-25T10:00:00Z"
  }
}

返回結構(data) ​

與註冊介面一致:user + token + expires_at

首次 Telegram 登錄且未綁定站內帳號時,系統會自動創建帳號並直接登錄。


4.6 Google 登入 ​

介面:POST /auth/google/login

認證:否

Body 參數 ​

欄位類型必填說明
credentialstring是Google Identity Services 回呼返回的不透明 ID Token;前端不得自行解析後信任其中聲明

請求範例 ​

json
{
  "credential": "eyJhbGciOiJSUzI1NiIs..."
}

成功回應範例 ​

無需二次驗證時:

json
{
  "status_code": 0,
  "msg": "success",
  "data": {
    "requires_totp": false,
    "user": {
      "id": 101,
      "email": "[email protected]",
      "nickname": "Google User",
      "email_verified_at": "2026-07-30T10:00:00Z"
    },
    "token": "eyJhbGciOi...",
    "expires_at": "2026-07-30T12:00:00Z"
  }
}

帳號已啟用 TOTP 時:

json
{
  "status_code": 0,
  "msg": "success",
  "data": {
    "requires_totp": true,
    "challenge_token": "eyJhbGciOi...",
    "challenge_expires_at": "2026-07-30T10:05:00Z"
  }
}

收到二次驗證挑戰後,繼續呼叫 POST /auth/login/verify-2fa。

後端會驗證 Google 簽章、aud、iss、有效期、sub 和郵箱驗證狀態。Gmail 地址及帶 hd 的 Google Workspace 地址可以安全地按郵箱關聯既有帳號;其他自訂網域同郵箱帳號必須先登入站內帳號,再透過綁定介面明確確認。首次建立帳號仍受註冊開關和郵箱網域白名單約束。

iOS/iPadOS redirect 登入 ​

桌面瀏覽器與 Android 使用上述 popup/FedCM credential 介面。iOS/iPadOS 使用以下 redirect form_post 流程:

  1. 前端呼叫 POST /auth/google/redirect/intent 建立一次性登入意圖。
  2. Google 向同源 POST /auth/google/redirect/callback 提交 credential、state 和 CSRF 欄位。
  3. 後端驗證並消費一次性 state 後,以 303 重新導向到前台固定路徑 /auth/google/callback?flow=login(失敗時僅追加白名單內的 error 代碼)。
  4. 前端呼叫 POST /auth/google/redirect/exchange,消費 HttpOnly handoff 並取得與 popup 登入相同的登入/2FA 回應。
建立登入意圖 ​

介面:POST /auth/google/redirect/intent

認證:否

Body:空 JSON 物件 {}。

json
{
  "status_code": 0,
  "msg": "success",
  "data": {
    "state": "c3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3M",
    "expires_in": 600,
    "issued_at": "2026-07-30T10:00:00Z"
  }
}

前端必須把返回的 state 原樣傳給 Google Identity Services 按鈕配置;同時後端會設定同源、Secure、HttpOnly 的 state Cookie。意圖只可使用一次。

Google form_post 回呼 ​

介面:POST /auth/google/redirect/callback

認證:否;此介面供 Google Identity Services 直接提交,不應由前端手動呼叫。

Content-Type:application/x-www-form-urlencoded

欄位類型必填說明
credentialstring是Google 返回的 ID Token
statestring是建立意圖時取得的一次性 state
g_csrf_tokenstring是必須與 Google 設定的同名 Cookie 一致

回呼不返回 JSON。後端完成 Google credential、雙提交 CSRF、state、租戶與流程驗證後,使用 303 See Other 跳轉到前台固定回呼頁。credential、state、handoff、站內 Token 均不會寫入重新導向 URL。

交換登入結果 ​

介面:POST /auth/google/redirect/exchange

認證:否

Body:空 JSON 物件 {};瀏覽器必須攜帶同源 Cookie。

成功回應與 POST /auth/google/login 完全相同,包括 TOTP challenge 分支。handoff 僅可交換一次,有效期為 120 秒。

redirect 登入依賴已啟用且可用的 Redis 7,透過 GETDEL 原子消費 state/handoff;Redis 不可用時這些 redirect 介面返回服務不可用。popup/FedCM 的 POST /auth/google/login 不依賴該狀態儲存。


5. 登錄用戶資料介面(需 Bearer Token) ​

5.1 獲取當前用戶 ​

介面:GET /me

認證:是

請求參數 ​

無

成功響應示例 ​

json
{
  "status_code": 0,
  "msg": "success",
  "data": {
    "id": 101,
    "email": "[email protected]",
    "nickname": "user",
    "email_verified_at": "2026-02-11T10:00:00Z",
    "locale": "zh-CN",
    "email_change_mode": "change_with_old_and_new",
    "password_change_mode": "change_with_old"
  }
}

返回結構(data) ​

  • data:UserProfile

5.2 登錄日誌列表 ​

介面:GET /me/login-logs

認證:是

Query 參數 ​

參數類型必填說明
pagenumber否頁碼
page_sizenumber否每頁條數

成功響應示例 ​

json
{
  "status_code": 0,
  "msg": "success",
  "data": [
    {
      "id": 1,
      "user_id": 101,
      "email": "[email protected]",
      "status": "success",
      "fail_reason": "",
      "client_ip": "127.0.0.1",
      "user_agent": "Mozilla/5.0",
      "login_source": "web",
      "request_id": "01HR...",
      "created_at": "2026-02-11T12:00:00Z"
    }
  ],
  "pagination": {
    "page": 1,
    "page_size": 20,
    "total": 1,
    "total_page": 1
  }
}

返回結構(data) ​

  • data:UserLoginLog[]
  • pagination:分頁對象

5.3 更新用戶資料 ​

介面:PUT /me/profile

認證:是

Body 參數 ​

字段類型必填說明
nicknamestring否暱稱
localestring否語言,例如 zh-CN

nickname 與 locale 至少傳一個。

請求示例 ​

json
{
  "nickname": "新暱稱",
  "locale": "zh-CN"
}

成功響應示例 ​

json
{
  "status_code": 0,
  "msg": "success",
  "data": {
    "id": 101,
    "email": "[email protected]",
    "nickname": "新暱稱",
    "email_verified_at": "2026-02-11T10:00:00Z",
    "locale": "zh-CN",
    "email_change_mode": "change_with_old_and_new",
    "password_change_mode": "change_with_old"
  }
}

返回結構(data) ​

  • data:UserProfile

5.4 獲取 Telegram 綁定狀態 ​

介面:GET /me/telegram

認證:是

請求參數 ​

無

成功響應示例(已綁定) ​

json
{
  "status_code": 0,
  "msg": "success",
  "data": {
    "bound": true,
    "provider": "telegram",
    "provider_user_id": "123456789",
    "username": "dujiao_user",
    "avatar_url": "https://t.me/i/userpic/320/xxx.jpg",
    "auth_at": "2026-02-20T12:00:00Z",
    "updated_at": "2026-02-20T12:00:00Z"
  }
}

成功響應示例(未綁定) ​

json
{
  "status_code": 0,
  "msg": "success",
  "data": {
    "bound": false
  }
}

返回結構(data) ​

字段類型說明
boundboolean是否已綁定 Telegram
providerstringOAuth 提供方(綁定時為 telegram)
provider_user_idstringTelegram 用戶 ID(字串)
usernamestringTelegram 用戶名
avatar_urlstringTelegram 頭像 URL
auth_atstringTelegram 授權時間
updated_atstring綁定資訊更新時間

當 bound=false 時,僅返回 bound 字段。


5.5 綁定 Telegram ​

介面:POST /me/telegram/bind

認證:是

Body 參數 ​

字段類型必填說明
idnumber是Telegram 用戶 ID
first_namestring否名
last_namestring否姓
usernamestring否Telegram 用戶名
photo_urlstring否Telegram 頭像 URL
auth_datenumber是Telegram 授權時間戳(秒)
hashstring是Telegram 登錄簽名

請求示例 ​

json
{
  "id": 123456789,
  "first_name": "Dujiao",
  "last_name": "User",
  "username": "dujiao_user",
  "photo_url": "https://t.me/i/userpic/320/xxx.jpg",
  "auth_date": 1739250000,
  "hash": "f1b2c3..."
}

成功響應示例 ​

json
{
  "status_code": 0,
  "msg": "success",
  "data": {
    "bound": true,
    "provider": "telegram",
    "provider_user_id": "123456789",
    "username": "dujiao_user",
    "avatar_url": "https://t.me/i/userpic/320/xxx.jpg",
    "auth_at": "2026-02-20T12:00:00Z",
    "updated_at": "2026-02-20T12:00:00Z"
  }
}

返回結構(data) ​

與 GET /me/telegram(已綁定)一致。


5.6 解除綁定 Telegram ​

介面:DELETE /me/telegram/unbind

認證:是

請求參數 ​

無

成功響應示例 ​

json
{
  "status_code": 0,
  "msg": "success",
  "data": {
    "unbound": true
  }
}

返回結構(data) ​

字段類型說明
unboundboolean是否解除綁定成功

僅當帳號仍有有效本機密碼,或另一個目前已啟用且配置完整的第三方登入方式時,才允許解除綁定 Telegram;否則後端會拒絕操作,避免帳號失去全部登入入口。


5.7 發送更換郵箱驗證碼 ​

介面:POST /me/email/send-verify-code

認證:是

Body 參數 ​

字段類型必填說明
kindstring是old(發到舊郵箱)/ new(發到新郵箱)
new_emailstring條件必填當 kind=new 時必填

當 email_change_mode=bind_only 時,kind=old 不可用,請直接使用 kind=new 綁定真實郵箱。

請求示例 ​

json
{
  "kind": "new",
  "new_email": "[email protected]"
}

成功響應示例 ​

json
{
  "status_code": 0,
  "msg": "success",
  "data": {
    "sent": true
  }
}

返回結構(data) ​

字段類型說明
sentboolean是否發送成功

5.8 更換郵箱 ​

介面:POST /me/email/change

認證:是

Body 參數 ​

字段類型必填說明
new_emailstring是新郵箱
old_codestring條件必填當 email_change_mode=change_with_old_and_new 時必填;當 bind_only 時可不傳(服務端忽略)
new_codestring是新郵箱驗證碼

請求示例 ​

json
{
  "new_email": "[email protected]",
  "old_code": "123456",
  "new_code": "654321"
}

成功響應示例 ​

json
{
  "status_code": 0,
  "msg": "success",
  "data": {
    "id": 101,
    "email": "[email protected]",
    "nickname": "user",
    "email_verified_at": "2026-02-11T10:00:00Z",
    "locale": "zh-CN",
    "email_change_mode": "change_with_old_and_new",
    "password_change_mode": "change_with_old"
  }
}

返回結構(data) ​

  • data:UserProfile

5.9 修改密碼 ​

介面:PUT /me/password

認證:是

Body 參數 ​

字段類型必填說明
old_passwordstring條件必填當 password_change_mode=change_with_old 時必填;當 set_without_old 時可不傳
new_passwordstring是新密碼

首次透過 Telegram 自動創建且未設置密碼的帳號,password_change_mode=set_without_old,僅需提交 new_password。

請求示例 ​

json
{
  "old_password": "OldPass123",
  "new_password": "NewPass123"
}

成功響應示例 ​

json
{
  "status_code": 0,
  "msg": "success",
  "data": {
    "updated": true
  }
}

返回結構(data) ​

字段類型說明
updatedboolean是否更新成功

5.10 取得 Google 綁定狀態 ​

介面:GET /me/google

認證:是

成功回應範例 ​

json
{
  "status_code": 0,
  "msg": "success",
  "data": {
    "bound": true,
    "provider": "google",
    "provider_user_id": "109876543210987654321",
    "username": "[email protected]",
    "email": "[email protected]",
    "display_name": "Google User",
    "avatar_url": "https://lh3.googleusercontent.com/a/example",
    "auth_at": "2026-07-30T10:00:00Z",
    "can_unbind": true
  }
}

can_unbind=false 表示解除綁定會使帳號失去全部可用登入方式,前端必須禁止解除綁定。


5.11 綁定 Google ​

介面:POST /me/google/bind

認證:是

Body 參數 ​

欄位類型必填說明
credentialstring是Google Identity Services 回呼返回的不透明 ID Token
json
{
  "credential": "eyJhbGciOiJSUzI1NiIs..."
}

成功回應與 GET /me/google 相同。若該 Google 身份已綁定其他用戶,或目前帳號已綁定另一 Google 身份,介面會拒絕操作。

iOS/iPadOS redirect 綁定 ​

redirect 綁定與登入共用 POST /auth/google/redirect/callback,但意圖和 exchange 均要求目前用戶認證:

  1. 呼叫 POST /me/google/redirect/intent 建立綁定意圖(Body 為 {},回應與登入意圖相同)。
  2. 將返回的 state 傳給 Google Identity Services,由 Google form_post 到同源 callback。
  3. callback 成功後以 303 重新導向到 /auth/google/callback?flow=bind。
  4. 呼叫 POST /me/google/redirect/exchange(Body 為 {})交換綁定結果,成功回應與 GET /me/google 相同。

建立和交換綁定意圖都必須攜帶 Bearer Token。一次性狀態同時綁定目前租戶與建立意圖的用戶;更換網域、租戶或用戶均不能完成交換。該流程同樣要求 Redis 7 可用。


5.12 解除綁定 Google ​

介面:DELETE /me/google/unbind

認證:是

僅當帳號仍有有效本地密碼或其他目前可用的第三方登入方式時允許解除綁定。

成功回應範例 ​

json
{
  "status_code": 0,
  "msg": "success",
  "data": {
    "unbound": true
  }
}

6. 登錄用戶訂單與支付介面(需 Bearer Token) ​

6.1 訂單金額預覽 ​

介面:POST /orders/preview

認證:是

Body 參數 ​

字段類型必填說明
itemsOrderItemInput[]是訂單項
coupon_codestring否優惠碼
manual_form_dataobject否人工交付表單提交值(見通用結構)

請求示例 ​

json
{
  "items": [
    {
      "product_id": 1001,
      "quantity": 1,
      "fulfillment_type": "manual"
    }
  ],
  "coupon_code": "SPRING2026",
  "manual_form_data": {
    "1001": {
      "receiver_name": "張三",
      "phone": "13277745648",
      "address": "廣東省深圳市南山區"
    }
  }
}

成功響應示例 ​

json
{
  "status_code": 0,
  "msg": "success",
  "data": {
    "currency": "CNY",
    "original_amount": "99.00",
    "discount_amount": "10.00",
    "promotion_discount_amount": "5.00",
    "total_amount": "84.00",
    "items": [
      {
        "product_id": 1001,
        "title": { "zh-CN": "奈飛會員" },
        "tags": ["熱門"],
        "unit_price": "99.00",
        "quantity": 1,
        "total_price": "99.00",
        "coupon_discount_amount": "10.00",
        "promotion_discount_amount": "5.00",
        "fulfillment_type": "manual"
      }
    ]
  }
}

返回結構(data) ​

  • data:OrderPreview

6.2 創建訂單 ​

介面:POST /orders

認證:是

Body 參數 ​

與 POST /orders/preview 相同。

請求示例 ​

json
{
  "items": [
    {
      "product_id": 1001,
      "quantity": 1,
      "fulfillment_type": "manual"
    }
  ],
  "manual_form_data": {
    "1001": {
      "receiver_name": "張三",
      "phone": "13277745648",
      "address": "廣東省深圳市南山區"
    }
  }
}

成功響應示例 ​

json
{
  "status_code": 0,
  "msg": "success",
  "data": {
    "order_no": "DN202602110001",
    "status": "pending_payment",
    "currency": "CNY",
    "original_amount": "99.00",
    "discount_amount": "0.00",
    "promotion_discount_amount": "0.00",
    "total_amount": "99.00",
    "expires_at": "2026-02-11T12:30:00Z",
    "items": [
      {
        "title": { "zh-CN": "奈飛會員" },
        "quantity": 1,
        "unit_price": "99.00",
        "total_price": "99.00",
        "coupon_discount_amount": "0.00",
        "promotion_discount_amount": "0.00",
        "fulfillment_type": "manual",
        "manual_form_schema_snapshot": {
          "fields": [
            { "key": "receiver_name", "type": "text", "required": true }
          ]
        },
        "manual_form_submission": {
          "receiver_name": "張三"
        }
      }
    ]
  }
}

返回結構(data) ​

  • data:Order

6.3 訂單列表 ​

介面:GET /orders

認證:是

Query 參數 ​

參數類型必填說明
pagenumber否頁碼
page_sizenumber否每頁條數
statusstring否狀態過濾(見 Order.status 枚舉)
order_nostring否訂單號模糊查詢

成功響應示例 ​

json
{
  "status_code": 0,
  "msg": "success",
  "data": [
    {
      "order_no": "DN202602110001",
      "status": "pending_payment",
      "currency": "CNY",
      "total_amount": "99.00",
      "created_at": "2026-02-11T12:00:00Z",
      "items": [
        {
          "title": { "zh-CN": "奈飛會員" },
          "quantity": 1,
          "unit_price": "99.00",
          "total_price": "99.00",
          "coupon_discount_amount": "0.00",
          "promotion_discount_amount": "0.00",
          "fulfillment_type": "manual",
          "manual_form_schema_snapshot": {},
          "manual_form_submission": {}
        }
      ]
    }
  ],
  "pagination": {
    "page": 1,
    "page_size": 20,
    "total": 1,
    "total_page": 1
  }
}

返回結構(data) ​

  • data:Order[]
  • pagination:分頁對象

6.4 訂單詳情 ​

介面:GET /orders/:order_no

認證:是

Path 參數 ​

參數類型必填說明
order_nostring是訂單號

成功響應示例 ​

json
{
  "status_code": 0,
  "msg": "success",
  "data": {
    "order_no": "DN202602110001",
    "status": "pending_payment",
    "currency": "CNY",
    "total_amount": "99.00",
    "items": [
      {
        "title": { "zh-CN": "奈飛會員" },
        "quantity": 1,
        "unit_price": "99.00",
        "total_price": "99.00",
        "coupon_discount_amount": "0.00",
        "promotion_discount_amount": "0.00",
        "fulfillment_type": "manual",
        "manual_form_schema_snapshot": {},
        "manual_form_submission": {}
      }
    ],
    "fulfillment": null,
    "children": []
  }
}

返回結構(data) ​

  • data:Order

6.5 取消訂單 ​

介面:POST /orders/:order_no/cancel

認證:是

Path 參數 ​

參數類型必填說明
order_nostring是訂單號

Body 參數 ​

無

成功響應示例 ​

json
{
  "status_code": 0,
  "msg": "success",
  "data": {
    "order_no": "DN202602110001",
    "status": "canceled",
    "currency": "CNY",
    "total_amount": "99.00",
    "canceled_at": "2026-02-11T12:10:00Z"
  }
}

返回結構(data) ​

  • data:Order

6.6 創建支付單 ​

介面:POST /payments

認證:是

Body 參數 ​

字段類型必填說明
order_nostring是訂單號
channel_idnumber是支付渠道 ID

請求示例 ​

json
{
  "order_no": "DN202602110001",
  "channel_id": 10
}

成功響應示例 ​

json
{
  "status_code": 0,
  "msg": "success",
  "data": {
    "payment_id": 3001,
    "provider_type": "official",
    "channel_type": "alipay",
    "interaction_mode": "page",
    "pay_url": "https://openapi.alipay.com/gateway.do?...",
    "qr_code": "",
    "expires_at": "2026-02-11T12:30:00Z"
  }
}

返回結構(data) ​

  • data:PaymentLaunch(創建支付時通常不含 order_no/channel_id 字段)

6.7 捕獲支付結果 ​

介面:POST /payments/:id/capture

認證:是

Path 參數 ​

參數類型必填說明
idnumber是支付記錄 ID

Body 參數 ​

無

成功響應示例 ​

json
{
  "status_code": 0,
  "msg": "success",
  "data": {
    "payment_id": 3001,
    "status": "success"
  }
}

返回結構(data) ​

字段類型說明
payment_idnumber支付記錄 ID
statusstring支付狀態:initiated / pending / success / failed / expired

6.8 獲取最新待支付記錄 ​

介面:GET /payments/latest

認證:是

Query 參數 ​

參數類型必填說明
order_nostring是訂單號

成功響應示例 ​

json
{
  "status_code": 0,
  "msg": "success",
  "data": {
    "payment_id": 3001,
    "order_no": "DN202602110001",
    "channel_id": 10,
    "provider_type": "official",
    "channel_type": "alipay",
    "interaction_mode": "page",
    "pay_url": "https://openapi.alipay.com/gateway.do?...",
    "qr_code": "",
    "expires_at": "2026-02-11T12:30:00Z"
  }
}

返回結構(data) ​

  • data:PaymentLaunch

7. 遊客訂單與支付介面 ​

遊客訂單訪問憑證為:email + order_password。

7.1 遊客訂單預覽 ​

介面:POST /guest/orders/preview

認證:否

Body 參數 ​

字段類型必填說明
emailstring是遊客郵箱
order_passwordstring是查詢密碼
itemsOrderItemInput[]是訂單項
coupon_codestring否優惠碼
manual_form_dataobject否人工交付表單提交值
captcha_payloadobject否驗證碼參數(當前預覽不會校驗,可忽略)

請求示例 ​

json
{
  "email": "[email protected]",
  "order_password": "guest-pass",
  "items": [
    {
      "product_id": 1001,
      "quantity": 1,
      "fulfillment_type": "manual"
    }
  ],
  "manual_form_data": {
    "1001": {
      "receiver_name": "張三",
      "phone": "13277745648",
      "address": "廣東省深圳市南山區"
    }
  }
}

成功響應示例 ​

與 POST /orders/preview 一致。

返回結構(data) ​

  • data:OrderPreview

7.2 遊客創建訂單 ​

介面:POST /guest/orders

認證:否

Body 參數 ​

與 POST /guest/orders/preview 相同。

請求示例 ​

json
{
  "email": "[email protected]",
  "order_password": "guest-pass",
  "items": [
    {
      "product_id": 1001,
      "quantity": 1,
      "fulfillment_type": "manual"
    }
  ],
  "manual_form_data": {
    "1001": {
      "receiver_name": "張三",
      "phone": "13277745648",
      "address": "廣東省深圳市南山區"
    }
  },
  "captcha_payload": {
    "captcha_id": "abc",
    "captcha_code": "x7g5",
    "turnstile_token": ""
  }
}

成功響應示例 ​

與 POST /orders 一致(遊客單的 guest_email 有值)。

返回結構(data) ​

  • data:Order

7.3 遊客訂單列表 ​

介面:GET /guest/orders

認證:否

Query 參數 ​

參數類型必填說明
emailstring是遊客郵箱
order_passwordstring是查詢密碼
order_nostring否訂單號,傳入時按單號查詢並返回 0/1 條
pagenumber否頁碼
page_sizenumber否每頁條數

成功響應示例 ​

json
{
  "status_code": 0,
  "msg": "success",
  "data": [
    {
      "order_no": "DN202602110002",
      "guest_email": "[email protected]",
      "status": "pending_payment",
      "currency": "CNY",
      "total_amount": "99.00",
      "items": [
        {
          "title": { "zh-CN": "奈飛會員" },
          "quantity": 1,
          "unit_price": "99.00",
          "total_price": "99.00",
          "coupon_discount_amount": "0.00",
          "promotion_discount_amount": "0.00",
          "fulfillment_type": "manual",
          "manual_form_schema_snapshot": {},
          "manual_form_submission": {}
        }
      ]
    }
  ],
  "pagination": {
    "page": 1,
    "page_size": 20,
    "total": 1,
    "total_page": 1
  }
}

返回結構(data) ​

  • data:Order[]
  • pagination:分頁對象

7.4 遊客訂單詳情 ​

介面:GET /guest/orders/:order_no

認證:否

Path 參數 ​

參數類型必填說明
order_nostring是訂單號

Query 參數 ​

參數類型必填說明
emailstring是遊客郵箱
order_passwordstring是查詢密碼

成功響應示例 ​

與用戶訂單詳情結構一致。

返回結構(data) ​

  • data:Order

7.5 遊客創建支付單 ​

介面:POST /guest/payments

認證:否

Body 參數 ​

字段類型必填說明
emailstring是遊客郵箱
order_passwordstring是查詢密碼
order_nostring是訂單號
channel_idnumber是支付渠道 ID

請求示例 ​

json
{
  "email": "[email protected]",
  "order_password": "guest-pass",
  "order_no": "DN202602110002",
  "channel_id": 10
}

成功響應示例 ​

與 POST /payments 返回結構一致。

返回結構(data) ​

  • data:PaymentLaunch

7.6 遊客捕獲支付結果 ​

介面:POST /guest/payments/:id/capture

認證:否

Path 參數 ​

參數類型必填說明
idnumber是支付記錄 ID

Body 參數 ​

字段類型必填說明
emailstring是遊客郵箱
order_passwordstring是查詢密碼

請求示例 ​

json
{
  "email": "[email protected]",
  "order_password": "guest-pass"
}

成功響應示例 ​

與 POST /payments/:id/capture 一致。

返回結構(data) ​

字段類型說明
payment_idnumber支付記錄 ID
statusstring支付狀態

7.7 遊客獲取最新待支付記錄 ​

介面:GET /guest/payments/latest

認證:否

Query 參數 ​

參數類型必填說明
emailstring是遊客郵箱
order_passwordstring是查詢密碼
order_nostring是訂單號

成功響應示例 ​

與 GET /payments/latest 一致。

返回結構(data) ​

  • data:PaymentLaunch

8. 前臺接入建議 ​

8.1 訂單介面統一使用 order_no ​

所有面向用戶的訂單介面均使用 order_no 作為標識符,不再暴露自增 ID:

  • GET /orders/:order_no — 訂單詳情
  • POST /orders/:order_no/cancel — 取消訂單
  • GET /orders/:order_no/fulfillment/download — 下載交付內容
  • GET /guest/orders/:order_no — 遊客訂單詳情
  • GET /guest/orders/:order_no/fulfillment/download — 遊客下載交付內容
  • POST /payments、GET /payments/latest — 使用 order_no 參數

8.2 統一錯誤處理 ​

前端必須同時判斷:

  • HTTP 狀態(網絡層)
  • status_code(業務層)

當 status_code != 0 時,請讀取 msg 提示並記錄 data.request_id 便於排查。

8.3 支付成功頁與輪詢 ​

建議支付流程組合使用:

  1. 發起支付後跳轉 pay_url 或展示 qr_code
  2. 支付完成回跳後,調用 capture
  3. 再調用 latest 兜底輪詢確認

可顯著降低「已支付但頁面未及時更新」的感知問題。


9. 非前臺主動調用介面(說明) ​

9.1 支付平臺回調介面 ​

以下回調介面一般由支付平臺服務器調用,前臺模板無需主動請求:

  • POST /payments/callback
  • GET /payments/callback
  • POST /payments/webhook/paypal
  • POST /payments/webhook/stripe

9.2 管理後臺 Telegram 登錄配置介面(Admin) ​

以下介面由管理後臺調用,不屬於前臺用戶側介面:

9.2.1 獲取 Telegram 登錄配置 ​

介面:GET /admin/settings/telegram-auth

認證:管理員 Token

成功響應示例 ​

json
{
  "status_code": 0,
  "msg": "success",
  "data": {
    "enabled": true,
    "bot_username": "dujiao_auth_bot",
    "bot_token": "",
    "has_bot_token": true,
    "login_expire_seconds": 300,
    "replay_ttl_seconds": 300
  }
}

返回中的 bot_token 會固定為脫敏空字串,是否已配置請以 has_bot_token 判斷。

9.2.2 更新 Telegram 登錄配置 ​

介面:PUT /admin/settings/telegram-auth

認證:管理員 Token

Body 參數(Patch) ​

字段類型必填說明
enabledboolean否是否啟用 Telegram 登錄
bot_usernamestring否Telegram Bot 用戶名(不帶 @)
bot_tokenstring否Telegram Bot Token(傳空字串不會覆蓋既有值)
login_expire_secondsnumber否登錄有效期(30-86400 秒)
replay_ttl_secondsnumber否重放保護時長(60-86400 秒)

請求示例 ​

json
{
  "enabled": true,
  "bot_username": "dujiao_auth_bot",
  "bot_token": "123456:ABCDEF",
  "login_expire_seconds": 300,
  "replay_ttl_seconds": 300
}

成功響應 ​

返回結構與 GET /admin/settings/telegram-auth 一致(脫敏)。

9.3 管理後臺商品多 SKU 介面(Admin) ​

以下介面由管理後臺調用,不屬於前臺使用者側介面。

9.3.1 建立商品(支援多 SKU) ​

介面:POST /admin/products認證:管理員 Token

Body 關鍵參數 ​

字段類型必填說明
category_idnumber是分類 ID
slugstring是商品唯一標識
titleobject是多語言標題
price_amountnumber是單規格模式下商品價格;多 SKU 時建議傳 0 或任意佔位值,最終以後端 SKU 計算為準
fulfillment_typestring否manual / auto
manual_stock_totalnumber否單規格模式下人工庫存總量
skusarray否多 SKU 陣列,傳空或不傳表示單規格模式

skus[] 字段 ​

字段類型必填說明
idnumber否更新既有 SKU 時傳;建立新 SKU 可不傳
sku_codestring是SKU 編碼(同商品內唯一)
spec_valuesobject否規格展示文案(如多語言 {"zh-TW":"標準版","en-US":"Standard"})
price_amountnumber是SKU 價格(必須大於 0)
manual_stock_totalnumber否SKU 人工庫存(手動交付模式下生效)
is_activeboolean否是否啟用,預設 true
sort_ordernumber否排序權重,預設 0;數值越大越靠前

請求示例(單規格相容) ​

json
{
  "category_id": 1,
  "slug": "vpn-monthly",
  "title": {
    "zh-CN": "VPN 月付",
    "zh-TW": "VPN 月付",
    "en-US": "VPN Monthly"
  },
  "price_amount": 29.9,
  "fulfillment_type": "manual",
  "manual_stock_total": 100
}

請求示例(多 SKU) ​

json
{
  "category_id": 1,
  "slug": "vpn-subscription",
  "title": {
    "zh-CN": "VPN 订阅",
    "zh-TW": "VPN 訂閱",
    "en-US": "VPN Subscription"
  },
  "price_amount": 0,
  "fulfillment_type": "manual",
  "skus": [
    {
      "sku_code": "STANDARD",
      "spec_values": {
        "zh-CN": "标准版",
        "zh-TW": "標準版",
        "en-US": "Standard"
      },
      "price_amount": 29.9,
      "manual_stock_total": 100,
      "is_active": true,
      "sort_order": 10
    },
    {
      "sku_code": "PRO",
      "spec_values": {
        "zh-CN": "专业版",
        "zh-TW": "專業版",
        "en-US": "Pro"
      },
      "price_amount": 49.9,
      "manual_stock_total": 80,
      "is_active": true,
      "sort_order": 20
    }
  ]
}

9.3.2 更新商品(支援多 SKU) ​

介面:PUT /admin/products/:id認證:管理員 Token

請求結構與 POST /admin/products 一致;若要更新既有 SKU,請在 skus[] 中傳對應 id。

9.3.3 後端處理規則 ​

  • 當 skus 非空時:
    • 商品展示價自動取「啟用 SKU 中的最低價」;
    • 若為人工交付,商品人工庫存總量自動彙總「啟用 SKU 的 manual_stock_total」。
  • 當 skus 為空時:
    • 按歷史單規格模式處理,價格與庫存使用商品本身字段。

9.3.4 管理後臺操作指引 ​

  1. 進入後臺 商品管理,新建或編輯商品。
  2. 在「SKU 規格設定」區域新增一個或多個 SKU,填寫編碼、規格文案、價格、庫存、狀態與排序。
  3. 若已配置 SKU,商品「價格/人工庫存總量」字段僅作展示參考,實際以 SKU 數據為準。
  4. 保存後可在前臺商品詳情頁按 SKU 展示與下單。

9.4 推廣返利介面(Affiliate) ​

以下介面對應前臺返利中心與後臺返利審核能力。

9.4.1 下單介面新增 affiliate_code 字段 ​

以下介面的請求體支持附帶 affiliate_code(聯盟 ID):

  • POST /orders/preview
  • POST /orders
  • POST /guest/orders/preview
  • POST /guest/orders

字段定義:

字段類型必填說明
affiliate_codestring否推廣聯盟 ID(如 AB12CD34),用於訂單返利歸因

9.4.2 公開點擊上報 ​

介面:POST /public/affiliate/click認證:無需登錄

字段類型必填說明
affiliate_codestring是聯盟 ID
visitor_keystring否訪客標識(前端可持久化)
landing_pathstring否落地路徑(如 /?aff=AB12CD34)
referrerstring否來源頁 URL

成功返回:

json
{
  "status_code": 0,
  "msg": "success",
  "data": {
    "ok": true
  }
}

9.4.3 用戶返利中心介面(需 Bearer Token) ​

A) 開通返利 ​
  • 介面:POST /affiliate/open
  • 說明:開通成功後返回返利檔案(含聯盟 ID)。
B) 獲取返利看板 ​
  • 介面:GET /affiliate/dashboard

返回 data 關鍵字段:

字段類型說明
openedboolean是否已開通
affiliate_codestring聯盟 ID
promotion_pathstring推廣路徑(如 /?aff=AB12CD34)
click_countnumber點擊數
valid_order_countnumber有效訂單數
conversion_ratenumber轉化率(百分比數值)
pending_commissionstring待確認佣金
available_commissionstring可提現佣金
withdrawn_commissionstring已提現佣金
C) 查詢我的佣金記錄 ​
  • 介面:GET /affiliate/commissions
  • 參數:page、page_size、status
  • status 可選值:pending_confirm / available / rejected / withdrawn
D) 查詢我的提現記錄 ​
  • 介面:GET /affiliate/withdraws
  • 參數:page、page_size、status
  • status 可選值:pending_review / rejected / paid
E) 申請提現 ​
  • 介面:POST /affiliate/withdraws
字段類型必填說明
amountstring是提現金額(字符串金額,保留 2 位小數)
channelstring是提現渠道
accountstring是提現賬號

9.4.4 管理後臺返利設置(Admin) ​

A) 獲取返利設置 ​
  • 介面:GET /admin/settings/affiliate
  • 認證:管理員 Token
B) 更新返利設置 ​
  • 介面:PUT /admin/settings/affiliate
  • 認證:管理員 Token
字段類型必填說明
enabledboolean是是否開啟返利
commission_ratenumber是返利比例(0-100,支持 2 位小數)
confirm_daysnumber是佣金確認天數(0-3650)
min_withdraw_amountnumber是最低提現金額(>=0)
withdraw_channelsstring[]是提現渠道列表

9.4.5 管理後臺返利管理(Admin) ​

以下介面均需管理員 Token:

介面說明
GET /admin/affiliates/users返利用戶列表
GET /admin/affiliates/commissions佣金記錄列表
GET /admin/affiliates/withdraws提現申請列表
POST /admin/affiliates/withdraws/:id/reject拒絕提現申請
POST /admin/affiliates/withdraws/:id/pay標記提現已打款

其中:

  • POST /admin/affiliates/withdraws/:id/reject body 支持 { "reason": "拒絕原因" }
  • POST /admin/affiliates/withdraws/:id/pay 無需額外 body 字段

9.5 管理後臺 Google 登入配置介面(Admin) ​

以下介面由管理後臺呼叫,需要 system_admin 權限。

9.5.1 取得 Google 登入配置 ​

介面:GET /admin/settings/google-auth

認證:管理員 Token

json
{
  "status_code": 0,
  "msg": "success",
  "data": {
    "enabled": true,
    "client_id": "1234567890-example.apps.googleusercontent.com"
  }
}

9.5.2 更新 Google 登入配置 ​

介面:PUT /admin/settings/google-auth

認證:管理員 Token

Body 參數(Patch) ​

欄位類型必填說明
enabledboolean否是否啟用 Google 登入
client_idstring否Google OAuth 2.0 Web Client ID;啟用時不能為空
json
{
  "enabled": true,
  "client_id": "1234567890-example.apps.googleusercontent.com"
}

儲存後配置立即生效。Client ID 是瀏覽器端公開標識,不需要 Client Secret;本功能也不請求 Gmail 郵箱權限。

Released under the GPLv3 License.