授權碼開放接口文檔
v1.0
授權碼開放接口文檔
本文面向需要把「支付 → 發碼 → 激活 → 校驗」做進自己軟件的開發者(客戶端軟件 / 僅推廣產品)。文檔按接口逐個說明調用時機、請求參數、返回字段、錯誤碼。
一、核心概念
| 概念 | 字段 / 術語 | 說明 |
|---|---|---|
| 軟件發碼密鑰 | licenseApiSecret |
產品開啟「授權激活」時系統自動生成,在開發者中心產品編輯表單可查看。軟件服務端用它計算 HMAC 簽名,平台用它驗簽;只能保存在你的軟件服務端,嚴禁寫入客戶端。 |
| 授權碼 | licenseCode |
平台生成的唯一授權碼,用戶憑它激活軟件。 |
| 機器碼 | machineCode |
客戶端軟件生成的設備標識(每台電腦唯一,建議對機器指紋做哈希,至少 8 位)。 |
| 激活憑證 | activationToken |
平台在激活 / 發碼時簽發的憑證,軟件保存後每次啟動校驗時回傳。 |
| 訂單號 | clientOrderId |
軟件內支付訂單號(客戶端或服務端生成)。平台按「產品 + 訂單號」冪等,防止重複扣費重複發碼。 |
二、接入準備
- 發佈產品時開啟「授權激活」,保存系統生成的軟件發碼密鑰(licenseApiSecret);
- 在發佈表單配置版本列表(如 BASIC/PRO/ULTIMATE)與升級策略(SAME_CODE 原碼升級 / NEW_CODE 換新碼);
- 將密鑰保存在軟件服務端,客戶端只保留授權碼與激活憑證。
三、接口總覽
接口前綴:https://www.powersoftware.app/frontApi(本地 / 測試環境按你的部署域名替換)。
| 接口 | 調用時機 | 鑒權 | 簽名 |
|---|---|---|---|
POST /license/software/generate |
軟件內支付成功後 | 無(驗簽) | 需要 |
POST /license/software/upgrade |
續費 / 升級版本支付成功後 | 無(驗簽) | 需要 |
POST /license/activate |
用戶首次激活 / 換新設備 | 無 | 不需要 |
POST /license/verify |
軟件每次啟動 | 無 | 不需要 |
POST /license/deactivate |
用戶解綁舊設備(個人中心) | 登入 | 不需要 |
四、簽名規則(發碼 / 升級接口必須)
簽名串:按以下固定順序、以換行符 \n 拼接(缺省字段填空值:edition 空串、expiryDays 填 0):
productId \n machineCode \n edition \n expiryDays \n clientOrderId \n licenseCode \n timestamp
簽名:HMAC-SHA256(軟件發碼密鑰 licenseApiSecret, 簽名串),結果用 Base64URL 編碼後放入 signature 字段。
防重放:timestamp 為毫秒時間戳,平台要求與服務器時間差不超過 5 分鐘,超時直接返回 signatureInvalid。
Node.js 示例:
const crypto = require("crypto");
const payload = [productId, machineCode, edition, expiryDays, clientOrderId, licenseCode, timestamp].join("\n");
const signature = crypto.createHmac("sha256", API_SECRET).update(payload).digest("base64url");
Python 示例:
import hashlib, hmac, base64
payload = "\n".join([str(productId), machineCode, edition, str(expiryDays), clientOrderId, licenseCode, str(timestamp)])
signature = base64.urlsafe_b64encode(hmac.new(API_SECRET.encode(), payload.encode(), hashlib.sha256).digest()).decode().rstrip("=")
(Base64URL 即標準 Base64 將 + 換 -、/ 換 _,並去掉末尾 = 填充。)
五、接口詳情
5.1 生成授權碼(軟件內支付後調用)
調用時機:用戶在軟件內完成支付後,由軟件服務端立即調用一次並保存返回的授權碼與激活憑證。同一訂單只應調用一次;重複調用因冪等不會重複發碼。
POST /license/software/generate
請求參數(JSON body):
| 參數 | 類型 | 必填 | 來源 | 說明 |
|---|---|---|---|---|
| productId | number | 是 | 軟件內置 / 服務端配置 | 產品 ID,與平台發佈的產品一致 |
| machineCode | string | 是 | 客戶端生成 | 當前設備機器碼,≥8 位 |
| edition | string | 否 | 客戶端支付時選擇 | 版本標識,須在產品版本列表內;缺省取產品默認第一個版本 |
| expiryDays | number | 否 | 客戶端支付時選擇 | 有效期天數,0=永久;範圍 0-3650 |
| clientOrderId | string | 是 | 客戶端 / 服務端生成 | 軟件內支付訂單號,1-64 字符;冪等鍵 |
| timestamp | number | 是 | 軟件服務端生成 | 毫秒時間戳 |
| signature | string | 是 | 軟件服務端計算 | HMAC 簽名,≥10 字符 |
成功響應 content 字段:
| 字段 | 類型 | 說明 |
|---|---|---|
| licenseId | number | 授權碼記錄 ID |
| licenseCode | string | 授權碼(寫入軟件授權信息) |
| productId | number | 產品 ID |
| edition | string | 版本標識 |
| machineId | number | 已綁定機器記錄 ID |
| activatedAt | string | 激活時間(ISO8601) |
| expiryTime | string/null | 到期時間(ISO8601),null=永久 |
| trialExpiryTime | string/null | 試用到期時間快照(ISO8601),null=非試用轉購買 |
| trialExpiryTime | string/null | 試用到期時間快照(ISO8601),null=非試用轉購買 |
| trialExpiryTime | string/null | 試用到期時間快照(ISO8601),null=非試用轉購買 |
| maxMachines | number | 最大可綁定機器數 |
| activationToken | string | 激活憑證,軟件保存用於啟動校驗 |
響應示例:
{
"code": "SUCCESS",
"requestId": "xxx",
"success": true,
"content": {
"licenseId": 1001,
"licenseCode": "AB12-CD34-EF56-GH78",
"productId": 88,
"edition": "PRO",
"machineId": 2001,
"activatedAt": "2026-08-05T10:00:00.000Z",
"expiryTime": "2027-08-05T10:00:00.000Z",
"trialExpiryTime": "2026-12-01T10:00:00.000Z",
"trialExpiryTime": "2026-12-01T10:00:00.000Z",
"trialExpiryTime": "2026-12-01T10:00:00.000Z",
"maxMachines": 1,
"activationToken": "eyJhbGciOiJIUzI1NiJ9..."
}
}
本接口錯誤碼:productIdRequired、machineCodeInvalid、orderIdRequired、productNotFound、productNotEnabled、apiSecretMissing、signatureInvalid、orderAlreadyUsed。
5.2 升級版本 / 續費(支付後調用)
調用時機:用戶在軟件內完成續費或升級版本支付後調用;同一訂單只應調用一次。
POST /license/software/upgrade
請求參數(JSON body):
| 參數 | 類型 | 必填 | 來源 | 說明 |
|---|---|---|---|---|
| productId | number | 是 | 軟件內置 / 服務端配置 | 產品 ID |
| licenseCode | string | 是 | 軟件本地保存 | 當前授權碼,≥10 位 |
| machineCode | string | 否 | 客戶端生成 | 當前機器碼;換新碼策略遷移綁定、補綁機器時傳 |
| edition | string | 是 | 客戶端支付時選擇 | 目標版本標識 |
| expiryDays | number | 否 | 客戶端支付時選擇 | 新增有效期天數,0=永久;範圍 0-3650 |
| clientOrderId | string | 是 | 客戶端 / 服務端生成 | 本次訂單號;冪等鍵 |
| timestamp | number | 是 | 軟件服務端生成 | 毫秒時間戳 |
| signature | string | 是 | 軟件服務端計算 | HMAC 簽名 |
處理策略(由產品配置決定):
- SAME_CODE(原碼升級):授權碼不變,機器綁定不失效,有效期順延(永久授權保持永久);響應在 5.1 字段基礎上增加
upgraded: true; - NEW_CODE(換新碼):吊銷舊碼、生成新碼並遷移機器綁定;響應額外返回
oldLicenseId,licenseCode為新碼。
成功響應 content 字段:與 5.1 相同,另加 upgraded: true;NEW_CODE 策略下返回 oldLicenseId(舊授權碼記錄 ID,舊碼已被吊銷)。
本接口錯誤碼:productIdRequired、licenseCodeRequired、orderIdRequired、productNotFound、productNotEnabled、apiSecretMissing、signatureInvalid、codeNotFound、revoked、orderAlreadyUsed、editionRequired。
5.3 激活授權(用戶首次激活 / 換新設備)
調用時機:用戶拿到授權碼(自助發碼、後台發碼等場景)後,在客戶端軟件激活頁輸入授權碼並激活;換新設備時在新設備調用。
POST /license/activate
請求參數(JSON body):
| 參數 | 類型 | 必填 | 來源 | 說明 |
|---|---|---|---|---|
| licenseCode | string | 是 | 用戶輸入 | 授權碼,≥10 位 |
| machineCode | string | 是 | 客戶端生成 | 當前設備機器碼,≥8 位 |
成功響應 content:同 5.1(licenseId、licenseCode、productId、edition、machineId、activatedAt、expiryTime、maxMachines、activationToken)。
說明:
- 同一授權碼可綁定多台機器,受
maxMachines限制(默認取產品配置); - 同一機器重複激活:復用原綁定並重新簽發激活憑證(冪等);
- 激活失敗會按 IP + 授權碼計數限流,多次失敗返回
tooManyAttempts。
本接口錯誤碼:codeNotFound、revoked、expired、machineLimit、tooManyAttempts。
5.4 校驗授權(軟件啟動時)
調用時機:軟件每次啟動(或解鎖功能前)調用;軟件須保存 5.1 / 5.2 / 5.3 返回的 activationToken。
POST /license/verify
請求參數(JSON body):
| 參數 | 類型 | 必填 | 來源 | 說明 |
|---|---|---|---|---|
| licenseCode | string | 是 | 軟件本地保存 | 授權碼,≥10 位 |
| machineCode | string | 是 | 客戶端生成 | 當前設備機器碼,≥8 位 |
| activationToken | string | 是 | 平台簽發、軟件保存 | 激活憑證,≥20 位 |
成功響應 content 字段:
| 字段 | 類型 | 說明 |
|---|---|---|
| valid | boolean | 恆為 true(失敗走錯誤碼) |
| licenseId | number | 授權碼記錄 ID |
| productId | number | 產品 ID |
| edition | string | 當前版本標識 |
| expiryTime | string/null | 到期時間(ISO8601),null=永久 |
| trialExpiryTime | string/null | 試用到期時間快照(ISO8601),null=非試用轉購買 |
| trialExpiryTime | string/null | 試用到期時間快照(ISO8601),null=非試用轉購買 |
| trialExpiryTime | string/null | 試用到期時間快照(ISO8601),null=非試用轉購買 |
說明:
- 校驗結果有約 60 秒緩存;吊銷、解綁、升級等寫操作會主動失效緩存,無需擔心延遲;
- 軟件應根據
expiryTime判斷是否過期,過期後停止解鎖功能。 - 若授權由試用轉購買,可結合
trialExpiryTime對高階功能做寬限:未過trialExpiryTime前繼續放行。 - 若授權由試用轉購買,可結合
trialExpiryTime對高階功能做寬限:未過trialExpiryTime前繼續放行。 - 若授權由試用轉購買,可結合
trialExpiryTime對高階功能做寬限:未過trialExpiryTime前繼續放行。
本接口錯誤碼:tokenInvalid、machineNotActivated、invalidOrRevoked、expired、tooManyAttempts。
5.5 解綁設備(換機前,需登入)
調用時機:用戶在「個人中心 → 我的授權」對舊設備執行解綁,然後在新設備調用 5.3 激活。
POST /license/deactivate
請求參數(JSON body):
| 參數 | 類型 | 必填 | 來源 | 說明 |
|---|---|---|---|---|
| licenseCode | string | 是 | 用戶授權列表 | 授權碼,≥10 位 |
| machineCode | string | 是 | 用戶授權列表 | 要解綁的機器碼,≥8 位 |
成功響應 content:true。
說明:
- 僅授權碼歸屬用戶(購買用戶或綁定機器碼登記用戶)可操作;
- 解綁配額:默認 30 天內僅可解綁 1 次(運營後台可配置),超限返回
unbindQuotaExceeded。
本接口錯誤碼:noPermission、machineNotBound、unbindQuotaExceeded。
六、錯誤碼匯總
業務錯誤統一返回(tip 為可讀錯誤信息):
{
"code": "BUSINESS_WARNING",
"requestId": "xxx",
"success": false,
"errorMessage": "LICENSE_GENERATE_FAILED",
"tip": "簽名校驗失敗"
}
參數校驗失敗返回 code: "PARAM_VALIDATE_FAILED",tip 為具體字段提示。
| 錯誤碼 | 含義 |
|---|---|
productNotEnabled |
產品未啟用授權激活 |
apiSecretMissing |
產品未配置軟件發碼密鑰(licenseApiSecret) |
signatureInvalid |
簽名校驗失敗(密鑰不一致、簽名串順序錯誤或時間戳超窗) |
machineCodeInvalid |
機器碼無效(長度不足 8 位) |
orderAlreadyUsed |
該訂單已生成過授權碼(冪等衝突:換機器碼重放) |
codeNotFound |
授權碼不存在 |
revoked |
授權碼已被吊銷或不可用 |
expired |
授權碼已過期 |
invalidOrRevoked |
校驗時授權無效或已被吊銷 |
machineNotActivated |
該機器未激活 |
tokenInvalid |
激活憑證無效 |
machineLimit |
授權碼綁定機器數已達上限 |
machineNotBound |
該機器未綁定 |
noPermission |
無權操作該授權碼 |
unbindQuotaExceeded |
30 天內僅可解綁 1 次,請稍後再試 |
tooManyAttempts |
嘗試次數過多,請稍後再試 |
productNotFound |
產品不存在 |
editionRequired |
請選擇目標版本 |
七、典型流程
- 軟件內支付閉環:支付成功 →
software/generate(返回授權碼 + 激活憑證)→ 軟件保存 → 每次啟動verify→ 解鎖功能;續費 / 升級 →software/upgrade; - 自助發碼 / 後台發碼:開發者中心或平台後台生成授權碼 → 用戶獲得授權碼 → 客戶端
activate綁定設備並獲取激活憑證 → 啟動verify; - 換機:個人中心
deactivate解綁舊設備 → 新設備activate→verify; - 升級策略差異:SAME_CODE 原碼升級(碼不變);NEW_CODE 換新碼(舊碼吊銷、新碼自動遷移機器綁定)。
八、注意事項
- 密鑰只存服務端:簽名只能在你的軟件服務端完成,客戶端拿到密鑰等於授權體系失效;
- 機器碼穩定性:建議使用穩定的機器指紋並做哈希;重裝系統導致機器碼變化時需先解綁再激活;
- 冪等:
clientOrderId請保證全局唯一(如 時間戳 + 隨機數),重複請求不會重複發碼; - 緩存:
verify結果緩存約 60 秒,寫操作即時失效; - 限流:激活 / 校驗失敗會限流,客戶端應做好錯誤提示與重試間隔;
- 以平台返回為準:有效期、版本、機器數上限等以平台判定為準,軟件端不要自行放寬。
六、先用后付(試用領取 / 購買頁跳轉)
客戶端軟件「先用後付」產品:用戶 0 元下載後由客戶端調用 POST /license/trial/claim 領取試用授權(productUniqueCode / machineCode,同產品+機器冪等)。
試用到期後付費功能需購買授權版本,購買頁:
https://www.powersoftware.app/product/license/purchase?productUniqueCode={productUniqueCode}&machineCode={machineCode}。
支付成功後平台發放正式授權碼並發送郵件。SDK 參考 ps-help/v3/doc/授权SDK规范_v3.md。
七、官方 SDK(Node / Python / Java)
三語言官方 SDK 與中英文規範:
https://github.com/mizhanchengxi/powersoftware-license-sdk
八、升級策略標識(licenseUpgradeMode)
POST /license/activate、POST /license/verify、POST /license/trial/claim 三個接口的成功響應 content 中附帶返回產品級升級策略配置:
| 字段 | 類型 | 說明 |
|---|---|---|
| licenseUpgradeMode | string | SAME_CODE=原碼不變(升級/續費後授權碼不變);NEW_CODE=原碼換綁(升級/續費吊銷舊碼、簽發新碼) |
客戶端用途:
- 據此決定是否展示「綁定授權碼」輸入框:
SAME_CODE下授權碼始終不變,無需引導用戶重新輸入;NEW_CODE下升級/續費會簽發新碼,須以接口返回的新licenseCode覆蓋本地保存的授權碼; verify每次啟動返回最新配置,客戶端可持續同步。
說明:
- 該字段為產品級配置(開發者在發布表單配置升級策略),未配置時按
SAME_CODE處理; verify結果緩存約 60 秒,平台修改配置後最長 60 秒生效;software/upgrade已按策略實際返回原碼或新碼,無需依賴該字段。
九、試用到期時間快照(trialExpiryTime)
POST /license/activate、POST /license/verify、POST /license/trial/claim 三個接口的成功響應 content 中附帶返回試用到期時間快照:
| 字段 | 類型 | 說明 |
|---|---|---|
| trialExpiryTime | string | null | 原試用授權的到期時間(ISO 8601);null = 非試用轉購買(含純首購、開發者發碼、試用未轉購買) |
產生規則:
- 領取試用時寫入,與試用授權的
expiryTime同值; - 試用後購買(原碼升級或換新碼)時,平台先查試用碼原到期時間並固化到本字段;購買後
expiryTime變為所購版本的有效期,本字段保持不變; - 過期試用轉購買同樣固化(值為過去時刻),客戶端可據此識別「無寬限」;
- 後續付費版本升級/續費(原碼或換新碼)保留該字段,鏈路不丟失。
客戶端用途(建議):先用後付產品試用期內全功能可用,購買較低版本後高檔功能會因版本門控立即鎖定。客戶端可讀取 trialExpiryTime 自行決定過渡策略,例如:所購版本不足以解鎖某高檔功能、且當前時間早於 trialExpiryTime 時,對該功能保留寬限放行,到達 trialExpiryTime 後再鎖定並引導補差價升級。是否使用、寬限方式由客戶端自行決定,平台不做強制。
另:領取試用時若該機器在該產品下已存在非試用授權(試用轉購買/首購/開發者發碼等,即已購買),接口返回錯誤碼 trialAlreadyPurchased,平台不再新增試用授權碼;已吊銷(退款)的授權不算已購。