授权码开放接口文档
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=永久 |
| 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",
"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=永久 |
说明:
- 校验结果有约 60 秒缓存;吊销、解绑、升级等写操作会主动失效缓存,无需担心延迟;
- 软件应根据
expiryTime判断是否过期,过期后停止解锁功能。
本接口错误码: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 秒,写操作即时失效; - 限流:激活 / 校验失败会限流,客户端应做好错误提示与重试间隔;
- 以平台返回为准:有效期、版本、机器数上限等以平台判定为准,软件端不要自行放宽。