API Reference
所有授权接口统一走 /api/v1/。客户端先拿到用户购买的卡密和本机 Device ID,再按 激活 → 每次启动验证 → 换设备换绑 → 到期后续期 接入。
每个请求必须带齐签名头。服务端用 API Secret 对原始请求体做 HMAC-SHA256,并校验 5 分钟内时间戳、Nonce 防重放、IP / API Key 限流。
| Header | 说明 |
|---|---|
| X-App-Id | 应用 ID,如 quant_pro |
| X-Api-Key | 应用 API Key |
| X-Timestamp | 毫秒时间戳,与服务器相差不超过 5 分钟 |
| X-Nonce | 随机字符串,同一 Key 10 分钟内不可重复 |
| X-Signature | HMAC-SHA256(secret, timestamp + "\\n" + nonce + "\\n" + rawBody) 的 hex |
限流:每个 IP 每分钟 120 次,每个 API Key 每分钟 60 次。黑名单 IP / Device / License / API Key 会被拦截。
/api/v1/license/activate使用卡密与 Device ID 创建 License 并绑定设备。同一设备重复激活会返回已有授权。
{
"app_id": "quant_pro",
"license_key": "K8F2-X7QM-92LA-P6TZ",
"device_id": "DEVICE-001",
"version": "1.0.0"
}TIMESTAMP=$(node -e "console.log(Date.now())")
NONCE=$(node -e "console.log(require('crypto').randomBytes(8).toString('hex'))")
BODY='{"app_id":"quant_pro","license_key":"K8F2-X7QM-92LA-P6TZ","device_id":"DEVICE-001","version":"1.0.0"}'
SIGN=$(node -e "const c=require('crypto');const t=process.argv[1],n=process.argv[2],b=process.argv[3];console.log(c.createHmac('sha256','demo_api_secret_quant_pro').update(t+'\\n'+n+'\\n'+b).digest('hex'))" "$TIMESTAMP" "$NONCE" "$BODY")
curl -X POST 'http://localhost:3000/api/v1/license/activate' \
-H 'Content-Type: application/json' \
-H 'X-App-Id: quant_pro' \
-H 'X-Api-Key: demo_api_key_quant_pro' \
-H "X-Timestamp: $TIMESTAMP" \
-H "X-Nonce: $NONCE" \
-H "X-Signature: $SIGN" \
-d "$BODY"{
"success": true,
"code": 0,
"message": "授权成功",
"data": {
"license_id": "LIC_123456",
"status": "active",
"expires_at": "2027-08-24T00:00:00.000Z",
"device_id": "DEVICE-001"
}
}/api/v1/license/verify软件每次启动时应调用。校验卡密、设备绑定和有效期。
{
"app_id": "quant_pro",
"license_key": "K8F2-X7QM-92LA-P6TZ",
"device_id": "DEVICE-001",
"version": "1.0.0"
}TIMESTAMP=$(node -e "console.log(Date.now())")
NONCE=$(node -e "console.log(require('crypto').randomBytes(8).toString('hex'))")
BODY='{"app_id":"quant_pro","license_key":"K8F2-X7QM-92LA-P6TZ","device_id":"DEVICE-001","version":"1.0.0"}'
SIGN=$(node -e "const c=require('crypto');const t=process.argv[1],n=process.argv[2],b=process.argv[3];console.log(c.createHmac('sha256','demo_api_secret_quant_pro').update(t+'\\n'+n+'\\n'+b).digest('hex'))" "$TIMESTAMP" "$NONCE" "$BODY")
curl -X POST 'http://localhost:3000/api/v1/license/verify' \
-H 'Content-Type: application/json' \
-H 'X-App-Id: quant_pro' \
-H 'X-Api-Key: demo_api_key_quant_pro' \
-H "X-Timestamp: $TIMESTAMP" \
-H "X-Nonce: $NONCE" \
-H "X-Signature: $SIGN" \
-d "$BODY"{
"success": true,
"code": 0,
"message": "授权有效",
"data": {
"status": "active",
"expires_at": "2027-08-24T00:00:00.000Z",
"days_remaining": 365,
"device_bound": true
}
}/api/v1/license/rebind将当前 License 从旧设备换到新设备,并消耗一次换绑次数。接口使用数据库事务,避免并发超扣。
{
"license_key": "K8F2-X7QM-92LA-P6TZ",
"device_id": "DEVICE-002"
}TIMESTAMP=$(node -e "console.log(Date.now())")
NONCE=$(node -e "console.log(require('crypto').randomBytes(8).toString('hex'))")
BODY='{"license_key":"K8F2-X7QM-92LA-P6TZ","device_id":"DEVICE-002"}'
SIGN=$(node -e "const c=require('crypto');const t=process.argv[1],n=process.argv[2],b=process.argv[3];console.log(c.createHmac('sha256','demo_api_secret_quant_pro').update(t+'\\n'+n+'\\n'+b).digest('hex'))" "$TIMESTAMP" "$NONCE" "$BODY")
curl -X POST 'http://localhost:3000/api/v1/license/rebind' \
-H 'Content-Type: application/json' \
-H 'X-App-Id: quant_pro' \
-H 'X-Api-Key: demo_api_key_quant_pro' \
-H "X-Timestamp: $TIMESTAMP" \
-H "X-Nonce: $NONCE" \
-H "X-Signature: $SIGN" \
-d "$BODY"{
"success": true,
"code": 0,
"message": "换绑成功",
"data": {
"device_id": "DEVICE-002",
"remaining_rebinds": 2
}
}/api/v1/license/renew用一张未激活的同商品卡密延长当前 License。未过期则从到期日叠加;已过期则从当前时间起算。永久套餐会将到期时间清空。
{
"app_id": "quant_pro",
"license_key": "K8F2-X7QM-92LA-P6TZ",
"renew_key": "B7K3-N4WP-8C5D-H9RF",
"device_id": "DEVICE-001"
}TIMESTAMP=$(node -e "console.log(Date.now())")
NONCE=$(node -e "console.log(require('crypto').randomBytes(8).toString('hex'))")
BODY='{"app_id":"quant_pro","license_key":"K8F2-X7QM-92LA-P6TZ","renew_key":"B7K3-N4WP-8C5D-H9RF","device_id":"DEVICE-001"}'
SIGN=$(node -e "const c=require('crypto');const t=process.argv[1],n=process.argv[2],b=process.argv[3];console.log(c.createHmac('sha256','demo_api_secret_quant_pro').update(t+'\\n'+n+'\\n'+b).digest('hex'))" "$TIMESTAMP" "$NONCE" "$BODY")
curl -X POST 'http://localhost:3000/api/v1/license/renew' \
-H 'Content-Type: application/json' \
-H 'X-App-Id: quant_pro' \
-H 'X-Api-Key: demo_api_key_quant_pro' \
-H "X-Timestamp: $TIMESTAMP" \
-H "X-Nonce: $NONCE" \
-H "X-Signature: $SIGN" \
-d "$BODY"{
"success": true,
"code": 0,
"message": "续期成功",
"data": {
"license_id": "LIC_123456",
"status": "active",
"expires_at": "2027-09-23T00:00:00.000Z"
}
}/api/v1/security/report客户端检测到反编译、调试器、完整性失败或破解补丁时调用。服务端会按上报的 Device ID 和卡密写入黑名单,并封禁对应授权。已封禁设备仍可上报。reason:decompile / debugger / integrity / crack / tamper。
{
"app_id": "quant_pro",
"license_key": "K8F2-X7QM-92LA-P6TZ",
"device_id": "DEVICE-001",
"reason": "decompile",
"detail": "detected unpacker"
}TIMESTAMP=$(node -e "console.log(Date.now())")
NONCE=$(node -e "console.log(require('crypto').randomBytes(8).toString('hex'))")
BODY='{"app_id":"quant_pro","license_key":"K8F2-X7QM-92LA-P6TZ","device_id":"DEVICE-001","reason":"decompile","detail":"detected unpacker"}'
SIGN=$(node -e "const c=require('crypto');const t=process.argv[1],n=process.argv[2],b=process.argv[3];console.log(c.createHmac('sha256','demo_api_secret_quant_pro').update(t+'\\n'+n+'\\n'+b).digest('hex'))" "$TIMESTAMP" "$NONCE" "$BODY")
curl -X POST 'http://localhost:3000/api/v1/security/report' \
-H 'Content-Type: application/json' \
-H 'X-App-Id: quant_pro' \
-H 'X-Api-Key: demo_api_key_quant_pro' \
-H "X-Timestamp: $TIMESTAMP" \
-H "X-Nonce: $NONCE" \
-H "X-Signature: $SIGN" \
-d "$BODY"{
"success": true,
"code": 0,
"message": "已记录并封禁",
"data": {
"report_id": "clx_report_1",
"reason": "decompile",
"banned": [
"device",
"license",
"license_key"
],
"license_id": "LIC_123456",
"device_id": "DEVICE-001"
}
}POST /api/v1/license/unbind 已列入规划,当前 MVP 未开放。需要清空设备时,请在后台「授权管理」使用「重置设备」,或走换绑接口绑定新设备。
统一响应:{ success, code, message, data }
| Code | 含义 |
|---|---|
| 0 | 成功 |
| 1001 | 无效卡密 |
| 1002 | 授权已过期 |
| 1003 | 授权已封禁 |
| 1004 | 设备不匹配 |
| 1005 | 超过设备数量 |
| 1006 | App 不存在 |
| 1007 | App 已停用 |
| 1008 | API Key 无效 / 签名错误 |
| 1009 | 请求频率过高 |
| 1010 | 请求参数错误 |
| 1011 | 换绑次数已用完 |
上方语言切换会同步所有接口示例。完整可运行脚本见仓库 scripts/license-demo.ts 与 docs/API.md。 OpenAPI 描述文件:/openapi.json