订阅快速入门
流程概览
1. 概述
订阅(Subscription):UtcPay 的订阅是商户在管理后台预先创建「订阅方案」,再通过接口为用户生成专属订阅链接,用户跳转后通过钱包完成签约和授权,商户通过签名机按方案设定的周期主动发起扣款,并在每次事件触发时回调商户。
流程: 👉 管理员后台 创建订阅方案 → 商户调用 createSubscribeOrder → 拼接订阅页面 URL → 用户跳转完成签约和授权 → 商户定时调用 查询待扣款订阅 + 签名机扣款 → 触发各类 订阅回调 → 商户处理。
注意:接口调用环节需要签名
2. 前提条件
-
开通商户账号:沙盒注册地址
-
获取 API Key / Secret:获取 API Key / Secret
-
需要配置 回调地址 (
notifyUrl) 和 跳转地址 (redirectionUrl) -
已在管理后台创建订阅方案(详见下方步骤 4)
-
已部署签名机服务(用于自动扣款,详见下方步骤 8)
-
确认使用的网络:
- 沙盒环境:
https://api-sandbox.utcpay.com/api/mer - 生产环境:
https://api.utcpay.com/api/mer
- 沙盒环境:
3. API 签名认证
所有请求需要在 Header 中添加:
| Header | 说明 |
|---|---|
X-PAY-KEY | 商户 API Key |
X-PAY-TIMESTAMP | 当前 Unix 时间戳(单位秒,误差 ≤ 60 秒) |
X-PAY-SIGN | 签名,规则请看下面「签名生成规则」 |
🔹 签名生成规则
参考官方文档:签名规则
- 拼接字符串
signString = timestamp + method + requestPath + body
timestamp:请求的 Unix 时间戳(秒)method:HTTP 方法,例如GET、POSTrequestPath:接口路径,不含域名,例如/api/mer/subscribe/payment/createbody:POST 请求的 JSON 字符串,GET 请求为空字符串
- 使用 HMAC-SHA256 算法
HMAC_SHA256(apiSecret, signString)
-
Base64 编码
将上一步得到的哈希值进行 Base64 编码,得到最终的
X-PAY-SIGN
🔹 请求头示例(HTTPS)
POST /api/mer/subscribe/payment/create
Host: api-sandbox.utcpay.com
Content-Type: application/json
X-PAY-KEY: <your_api_key>
X-PAY-TIMESTAMP: 1723971200
X-PAY-SIGN: <生成的签名>
🔹 注意事项
- 所有 POST 请求需带
Content-Type: application/json timestamp与服务器时间差值不能超过 60 秒,防止重放攻击body必须是有效 JSON,否则签名验证会失败
4. 创建订阅方案(管理员后台)
订阅方案需要在管理后台预先创建,方案上链后商户才能调用接口生成订阅链接。
💡 订阅方案需要多签审批后才会上链生效,请确保至少有两个管理员账号。
🔹 步骤 1:登录管理员后台
登录后右上角可确认当前链和钱包地址。
🔹 步骤 2:进入订阅方案
顶部导航:支付工具 → 订阅方案

🔹 步骤 3:创建订阅方案
点击「增加」按钮,填写方案参数后点击「提交」。 钱包弹出 Signature request,确认参数无误后点击 Confirm 完成第一签。

方案 ID 需要商户自己填写,必须保证在商户侧唯一且不变(只能使用数字 ID)。后续接口调用需要用到该方案 ID。
🔹 步骤 4:多签审批
切换到 另一个管理员账号 登录后台,进入 支付工具 → 订阅方案 列表,对该方案发起审批,钱包再次签名确认。

多签审批通过后,方案参数才会真正上链生效。审批前方案处于待审批状态,无法被使用。
🔹 步骤 5:创建成功
多签通过后,方案状态变为「正常」,可被商户用于创建订阅链接。记录方案 ID,后续接口调用需要用到。

5. 创建订阅链接(createSubscribeOrder)
请求体参数说明
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
chainId | int32 | 是 | 平台内部链 ID,可从查询链列表接口获取 |
planId | int64 | 是 | 订阅方案 ID |
externalUserId | string | 是 | 商户侧用户标识 |
redirectionUrl | uri | 是 | 用户订阅成功后的跳转地址 |
notifyUrl | uri | 是 | 商户回调地址,必须为公网可访问 HTTPS 地址 |
请求示例
POST /api/mer/subscribe/payment/create
Host: api-sandbox.utcpay.com
Content-Type: application/json
X-PAY-KEY: your_api_key
X-PAY-TIMESTAMP: 1723971200
X-PAY-SIGN: RlpTCwGT7lECP7achGM4oqT+Y5fXYjOqTRAJ9VPdY2U=
请求体示例
{
"chainId": 1,
"planId": 3,、
"externalUserId": "USER10001",、
"redirectionUrl": "https://merchant.com/subscribe-success",
"notifyUrl": "https://merchant.com/api/subscription-callback"
}
响应示例
{
"code": 200,
"msg": "操作成功",
"data": {
"subscriptionId": 123,
"paymentUrl": "/subscription?apiSign=CSetiUau5zInfAZukEGsSfelBSmlVB3XVh5t7Ozoits%3D",
"expiration": 1723974800
}
}
说明:
paymentUrl→ 订阅页面路径,需要拼接官方域名才能访问subscriptionId→ UtcPay 订阅订单号(保存以便查询)expiration→ 链接过期时间戳
💡 订阅之前不需要预先为用户创建子合约地址,用户在订阅页面连接钱包即可完成签约。
externalUserId仅作为商户侧的用户标识。
🔹 拼接订阅页面 URL
返回的 paymentUrl 是相对路径,必须拼接 UtcPay 官方域名才能访问:
- 正式环境:
https://payment.utcpay.com+paymentUrl - 沙盒环境:
https://payment-sandbox.utcpay.com+paymentUrl
例如:
https://payment.utcpay.com/subscription?apiSign=CSetiUau5zInfAZukEGsSfelBSmlVB3XVh5t7Ozoits%3D
请勿直接使用返回的 paymentUrl,必须拼接官方域名以避免误用或安全风险。
🔹 集成到商户平台
将拼接好的 URL 加到商户自己的订阅平台,例如增加一个「USDT 支付」按钮跳转到该链接:
<a href="https://payment.utcpay.com/subscription?apiSign=...">
USDT 支付
</a>
用户点击后跳转到 UtcPay 订阅页面,完成 确认方案 → 签约 → 授权额度 三步流程。

💡 在沙盒环境中,您可以领取测试代币用于模拟订阅交易:
- 参考测试币领取教程。
- 根据当前选择的链(Tron Nile 或 Ethereum Sepolia),打开对应的官方水龙头网站。
- 输入您的测试钱包地址,领取测试代币(USDT、ETH、TRX 等)。
- 使用领取的测试代币,通过生成的
paymentUrl进行订阅,完成订阅流程的测试。
提示:所有测试网代币仅可用于沙盒测试环境,不具备实际价值。
提示:测试网和主网是完全独立的区块链网络,切勿将主网资产发送到测试网地址,反之亦然。
6. 订阅回调(subscriptionCallback)
UtcPay 会异步 POST 到 notifyUrl,商户收到后需:
- 校验
sign签名是否合法 - 根据
subscriptionType处理对应业务逻辑 - 返回 HTTP 200 并响应
success确认
🔹 回调类型说明
通过 subscriptionType 字段区分回调类型:
| subscriptionType | 触发时机 | 商户处理建议 |
|---|---|---|
SubscriptionRegister | 用户在订阅页面完成签约 | 记录订阅关系,标记用户已签约 |
SubscriptionApprove | 用户完成钱包授权扣款额度 | 标记授权状态,订阅生效 |
SubscriptionBilling | 每次周期扣款完成(含首期) | 更新用户订阅有效期,发放权益 |
SubscriptionCancel | 用户主动退订 | 标记订阅已取消,停止后续服务 |
🔹 回调示例
{
"subscriptionType": "SubscriptionBilling",
"outTradeNo": "SUB202508191519455758358",
"externalUserId": "USER10001",
"planId": 3,
"planVersion": 1,
"chainId": 1,
"userWallet": "0xF631...90A9",
"amount": "1000000",
"currencySymbol": "USDT",
"transferHash": "0x928b3243...",
"blockTime": 1712122830,
"createTime": "2025-08-19 15:19:45"
}
🔹 重试策略
回调最多发送 6 次,分别在事件确认后的 0 秒、15 秒、30 秒、3 分钟、5 分钟、10 分钟 时发送。
当商户正常返回 success 时,系统会认为回调成功,不再发送后续回调。
📌 商户需要验证回调通知的签名,确保通知的安全性,回调的加签方式与普通请求一致。
7. 自动扣费流程
订阅创建成功且用户完成授权后,商户需要 主动调用扣款流程 触发周期性扣费。整体分两步:查询待扣款订阅 → 调用签名机扣款。签名机内部会自动广播交易上链,商户无需手动处理。
💡 调用频率由商户自定,按业务实际需要触发即可(例如每小时、每日定时任务)。
🔹 流程概览
商户定时任务
↓
1. getChargeableSubscriptionList 查询待扣款订阅
↓
2. signProcessSubscribePlan 调用签名机扣款(按链区分 EVM/TVM)
↓
成功 → 签名机自动广播上链 → SubscriptionBilling 回调(成功)
失败 → 返回失败原因 → SubscriptionBilling 回调(失败)
🔹 查询待扣款订阅列表
getChargeableSubscriptionList 接口文档
商户定时调用此接口,获取需要扣款的订阅列表。
GET /api/mer/subscribe/chargeable/list?page=1&size=20
Host: api-sandbox.utcpay.com
X-PAY-KEY: your_api_key
X-PAY-TIMESTAMP: 1723971200
X-PAY-SIGN: <生成的签名>
返回的列表中每条订阅都包含 subscribeId 和必要的链上信息,作为下一步调用签名机的输入。
🔹 调用签名机进行扣款
签名机需要按链区分调用接口:
- EVM 链(ETH):
POST /PayTool/EVM/subscribe/signProcessSubscribePlan - TVM 链(TRON):
POST /PayTool/TVM/subscribe/signProcessSubscribePlan
接口文档:
将查询到的待扣款订阅信息传入签名机,签名机会完成 签名 + 自动广播 整个流程。
🔹 扣款响应说明
✅ 扣款成功(code = 1)
{
"code": 1,
"msg": "SUCCESS",
"data": {
"address": "0xf0d2db2740ca0cd94e76c1af85fc9e5ef88ee011",
"chainId": 139,
"gasRequired": "117803",
"signedTransactionData": "0xf8cc3983e441a88301cc2b943e8d3c579817fa235901096c64107c8c8867554f80b86452429e7f...",
"subscriptionIds": [49],
"txHash": "0xe222a81f39b38cc50a14a3539086066bcf4d0a2582dc5a81abab27ef158f4ed9"
},
"description": null
}
字段说明:
signedTransactionData→ 已签名的交易数据(签名机内部自动广播,无需商户手动处理)subscriptionIds→ 本次扣款覆盖的订阅 ID 列表txHash→ 链上交易哈希(可用于后续追踪和对账)gasRequired→ 此次交易消耗的 Gas
扣款成功后等待 UtcPay 触发 SubscriptionBilling 回调即可。
❌ 扣款失败(code = 2)
{
"code": 2,
"msg": "SUCCESS",
"data": [
{
"amount": 8000000,
"failReason": "Allowance insufficient",
"planId": 6,
"subscribeId": 44,
"tokenAllowance": "0",
"tokenBalance": "944000000",
"userHash": "0xde1469a7d688f10c46f3a25f12c23bce48dfc52f999031664cca22df931a4382"
}
],
"description": null
}
返回数组列出每个无法扣款的订阅及具体原因。常见 failReason:
| failReason | 说明 | 商户处理建议 |
|---|---|---|
Allowance insufficient | 用户授权额度不足 | 引导用户重新授权或退订 |
Balance insufficient | 用户钱包余额不足 | 通知用户补充余额或停止服务 |
无论扣款成功还是失败,UtcPay 都会发送 subscriptionType=SubscriptionBilling 的回调到商户的 notifyUrl,商户需要据此 更新订阅状态、发放服务或停止权益。回调的处理逻辑参见上文章节 6 订阅回调。
8. 部署签名机
签名机是用于 安全管理私钥并签名链上交易 的服务,由商户自行部署运行。订阅自动扣款依赖签名机完成签名和广播。
签名机需要在调用扣款流程前预先部署完成并正常运行。
部署完成后,签名机会暴露 HTTP 接口供商户调用:
- 签名 EVM 订阅扣款:
POST /PayTool/EVM/subscribe/signProcessSubscribePlan - 签名 TVM 订阅扣款:
POST /PayTool/TVM/subscribe/signProcessSubscribePlan
完整签名机接口列表参见:签名机 API 参考
9. 创建退订链接(createUnsubscribeOrder)
请求体参数说明
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
outTradeNo | string | 是 | UtcPay 订阅订单号 |
redirectionUrl | uri | 是 | 用户退订成功后的跳转地址 |
notifyUrl | uri | 是 | 商户回调地址,必须为公网可访问 HTTPS 地址 |
请求示例
POST /api/mer/subscribe/cancel/create
Host: api-sandbox.utcpay.com
Content-Type: application/json
X-PAY-KEY: your_api_key
X-PAY-TIMESTAMP: 1723971200
X-PAY-SIGN: <生成的签名>
请求体示例
{
"outTradeNo": "SUB202508191519455758358",
"redirectionUrl": "https://merchant.com/unsubscribe-success",
"notifyUrl": "https://merchant.com/api/subscription-callback"
}
响应示例
{
"code": 200,
"msg": "操作成功",
"data": {
"paymentUrl": "/unsubscription?apiSign=...",
"expiration": 1723974800
}
}
退订链接的拼接规则与订阅链接一致:
- 正式环境:
https://payment.utcpay.com+paymentUrl - 沙盒环境:
https://payment-sandbox.utcpay.com+paymentUrl
将拼接好的 URL 提供给用户(例如商户订阅管理页面的「取消订阅」按钮),用户跳转后通过钱包取消授权完成退订。
退订完成后,商户会收到 subscriptionType=SubscriptionCancel 的回调通知。
10. 查询订阅信息
✅ 至此,你就完成了 订阅完整流程: