购买套餐
{{dashboard.subscription?('当前套餐:'+dashboard.subscription.plan_name+' · 到期 '+fmt(dashboard.subscription.expires_at)):'先购买有效套餐,开启站点创建和收款能力。'}}
TRC20 单钱包直收、精确金额识别、链上确认和签名回调。平台不托管资金。
{{authMode==='login'?'登录后管理站点与支付订单':'注册后请先完成邮箱验证'}}
按顺序完成套餐、钱包、站点和接口接入;下方继续保留经营数据。
{{dashboard.subscription?('当前套餐:'+dashboard.subscription.plan_name+' · 到期 '+fmt(dashboard.subscription.expires_at)):'先购买有效套餐,开启站点创建和收款能力。'}}
新增 USDT-TRC20 或 Binance 钱包,作为用户付款的收款方式。
填写站点名称、回调地址和返回地址,并选择可用钱包。
保存 API Key、API Secret 和 Webhook Secret,由服务端创建支付订单。
按创建时间统计,深色为成功支付订单
当前账户全部支付订单分布
站点、钱包和套餐用量
按收款金额和订单数排序
最新 6 笔商户支付订单
| 支付编号 | 站点 | 标题 | 金额 | 状态 | 创建时间 |
|---|---|---|---|---|---|
| {{o.payment_id}} | {{o.site_name}} | {{o.subject}} | {{o.pay_amount}} USDT | {{payStatusText(o.status)}} | {{fmt(o.created_at)}} |
| 暂无订单 | |||||
有效期内续费会从当前到期时间累加
{{plan.description}}
未完成订单可继续支付或取消
| 订单号 | 套餐 | 应付金额 | 状态 | 到期 | 操作 |
|---|---|---|---|---|---|
| {{o.order_no}} | {{o.plan_name}} | {{o.pay_amount}} USDT | {{payStatusText(o.status)}} | {{fmt(o.expires_at)}} | - |
| 暂无购买记录 | |||||
先维护钱包类型和地址,站点只选择钱包类型
| 钱包类型 | 名称 | 账号 / 地址 | 状态 | 操作 |
|---|---|---|---|---|
| {{w.wallet_type}} {{walletProviderLabel(w)}} · {{walletDetail(w)}} | {{w.name}} | {{walletDisplay(w)}} | {{w.status}} | |
| 尚未配置钱包 | ||||
每个站点拥有独立密钥,并从钱包配置中选择收款类型
| 站点 | 钱包类型 | API Key | 状态 | 操作 |
|---|---|---|---|---|
| {{s.name}} | {{s.wallets&&s.wallets.length?('已选 '+s.wallets.length+' 个钱包'):'未选择'}} {{s.wallet_name||short(s.wallet_address)}} | {{s.api_key}} | {{s.status}} | |
| 尚未创建站点 | ||||
查看链上确认与回调状态
| 支付编号 | 商户订单 | 标题 | 应付金额 | 网络 | 状态 | 倒计时 | 操作 | 确认数 | 创建时间 |
|---|---|---|---|---|---|---|---|---|---|
| {{o.payment_id}} | {{o.merchant_order_no}} | {{o.subject}} | {{o.pay_amount}} | {{o.network}} | {{o.status}} | {{orderCountdown(o)}} | - | {{o.confirmations}} | {{fmt(o.created_at)}} |
| 暂无订单 | |||||||||
处理用户在支付页提交的问题反馈
| 工单号 | 支付订单 | 站点 | 问题原因 | 状态 | 提交时间 | 操作 |
|---|---|---|---|---|---|---|
| {{t.ticket_no}} | {{t.payment_id}} {{t.merchant_order_no}} | {{t.site_name}} | {{t.reason}} | {{ticketStatusText(t.status)}} | {{fmt(t.created_at)}} | |
| 暂无工单 | ||||||
默认使用快速接入:创建订单、拿到 checkout_url、跳转收银台,支付结果以 Webhook 为准。
{{apiOrigin}}/api/v1根据你的站点类型选择最短路径
推荐默认使用,字段最少,适合大多数商户
所有支付订单都必须由服务端创建。平台返回 checkout_url 后,你的网站再把用户跳转过去。
{{apiOrigin}}/api/v1/simple/paymentsAuthorization: Bearer 你的 API Secret{
"order_no": "site_order_202609200001",
"amount": "100.00",
"title": "商品标题"
}| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
order_no | string | 是 | 你的系统订单号。同一站点内必须唯一,用于 Webhook 回调后匹配本地订单。 |
amount | decimal string | 是 | 订单原始金额,单位 USDT。最多 2 位小数,例如 100.00。 |
title | string | 是 | 订单标题,会在后台和订单查询中展示,建议传商品名或订单摘要。 |
notify_url | url | 否 | 代码里的回调地址。后台站点已配置时,后台优先;只有后台留空才使用这里。 |
return_url | url | 否 | 用户付款后返回你网站的页面。不能作为发货依据,真实状态以 Webhook 或查询接口为准。 |
expires_in | integer | 否 | 订单过期秒数,范围 300 到 86400。不传时使用平台默认值。 |
使用 HMAC 签名、时间戳和 Nonce 做请求校验
高级接口使用 HMAC 签名,适合需要更强请求校验的商户系统。
{{apiOrigin}}/api/v1/paymentsX-API-Key + X-Signature{
"merchant_order_no": "site_order_202609200001",
"amount": "100.00",
"network": "TRC20",
"subject": "商品标题",
"notify_url": "https://example.com/bestupay/notify",
"return_url": "https://example.com/orders/site_order_202609200001",
"expires_in": 1800
}| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
merchant_order_no | string | 是 | 你的系统订单号。同一站点内必须唯一,重复创建会返回已存在订单的 payment_id。 |
amount | decimal string | 是 | 订单原始金额,单位 USDT。最多 2 位小数,例如 100.00。 |
network | string | 是 | 当前支持 TRC20。快速接口默认使用 TRC20。 |
subject | string | 是 | 订单标题,展示在后台订单列表和订单详情中。 |
notify_url | url | 否 | 代码里的回调地址。后台站点已配置时,后台优先;只有后台留空才使用这里。 |
return_url | url | 否 | 用户付款后返回你网站的页面。不能作为发货依据。 |
expires_in | integer | 否 | 订单过期秒数,范围 300 到 86400。不传时使用平台默认值。 |
创建成功后直接 302 跳转或返回给前端跳转
$payload = [
'order_no' => 'site_order_202609200001',
'amount' => '100.00',
'title' => 'Product title',
];
$ch = curl_init('https://your-domain.com/api/v1/simple/payments');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'Authorization: Bearer ' . $apiSecret,
],
CURLOPT_POSTFIELDS => json_encode($payload, JSON_UNESCAPED_SLASHES),
]);
$res = json_decode(curl_exec($ch), true);
header('Location: ' . $res['data']['checkout_url']);
const payload = {
order_no: 'site_order_202609200001',
amount: '100.00',
title: 'Product title'
};
const res = await fetch('https://your-domain.com/api/v1/simple/payments', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${apiSecret}`
},
body: JSON.stringify(payload)
});
const json = await res.json();
response.redirect(json.data.checkout_url);
import requests
payload = {
"order_no": "site_order_202609200001",
"amount": "100.00",
"title": "Product title",
}
res = requests.post(
"https://your-domain.com/api/v1/simple/payments",
json=payload,
headers={"Authorization": f"Bearer {api_secret}"},
)
checkout_url = res.json()["data"]["checkout_url"]
String body = """
{"order_no":"site_order_202609200001","amount":"100.00","title":"Product title"}
""";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://your-domain.com/api/v1/simple/payments"))
.header("Content-Type", "application/json")
.header("Authorization", "Bearer " + apiSecret)
.POST(HttpRequest.BodyPublishers.ofString(body))
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
body := strings.NewReader(`{"order_no":"site_order_202609200001","amount":"100.00","title":"Product title"}`)
req, _ := http.NewRequest("POST", "https://your-domain.com/api/v1/simple/payments", body)
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer "+apiSecret)
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
商户 API 请求头:
X-API-Key: 你的 API Key X-Timestamp: 当前 Unix 秒级时间戳 X-Nonce: 每次请求唯一随机字符串 X-Signature: HMAC-SHA256 签名
METHOD|/api/v1/payments|timestamp|nonce|sha256(rawBody)| 请求头 | 说明 |
|---|---|
X-API-Key | 站点 API Key,用于定位商户站点。 |
X-Timestamp | 当前 Unix 秒级时间戳,超出允许窗口会被拒绝。 |
X-Nonce | 每次请求唯一随机字符串,已使用的 Nonce 不能重复。 |
X-Signature | 使用 API Secret 对签名原文计算 HMAC-SHA256 后转小写十六进制。 |
GET 请求没有 body 时,rawBody 按空字符串计算。
创建成功后使用 checkout_url 跳转用户付款
{
"success": true,
"data": {
"payment_id": "pay_xxxxxxxxxxxxxxxxxxxxxxxx",
"checkout_url": "https://pay.example.com/checkout/?payment_id=pay_xxx",
"address": "T...",
"requested_amount": "100.000000",
"pay_amount": "100.003421",
"qr_content": "T...",
"expires_at": "2026-09-20T21:34:46+08:00"
}
}| 字段 | 说明 |
|---|---|
payment_id | 平台支付订单号,用于查询订单、取消订单和拼接收银台链接。 |
checkout_url | 用户付款页面。你的网站应跳转到这个地址,不要让终端用户自己拼接支付链接。 |
requested_amount | 原始订单金额,单位 USDT。 |
pay_amount | 用户需要精确支付的金额。平台会加唯一小数尾数用于识别订单。 |
address | 创建订单时选中的收款地址或钱包地址快照。 |
expires_at | 订单过期时间,ISO 8601 格式。 |
| 接口 | 用途 | 鉴权 |
|---|---|---|
GET /api/v1/payments/{payment_id} | 查询单笔订单状态 | HMAC |
GET /api/v1/payments?status=pending | 按状态分页查询订单 | HMAC |
POST /api/v1/payments/{payment_id}/cancel | 取消仍处于 pending 的订单 | HMAC |
真实支付结果以 Webhook 或服务端查询为准
订单状态变化后平台向 notify_url 推送 JSON。验签成功后再更新本地订单,并返回 HTTP 2xx。
X-BestuPay-Signature: HMAC-SHA256(raw JSON body, Webhook Secret) X-BestuPay-Event: 回调事件 ID
{
"event_id": "evt_xxxxxxxxxxxxxxxxxxxxxxxx",
"event_type": "payment.paid",
"payment_id": "pay_xxx",
"merchant_order_no": "site_order_202609200001",
"status": "paid",
"requested_amount": "100.000000",
"pay_amount": "100.003421",
"received_amount": "100.003421",
"address": "T...",
"timestamp": 1790000000,
"tx_hash": "..."
}| 字段 | 说明 |
|---|---|
event_id | 回调事件 ID,建议用于幂等处理,避免重复发货。 |
event_type | 事件类型,例如 payment.paid、payment.expired。 |
payment_id | 平台支付订单号。 |
merchant_order_no | 你的系统订单号。快速接口对应 order_no。 |
status | 订单最新状态。发货通常只接受 paid。 |
requested_amount | 原始订单金额。 |
pay_amount | 用户应付的精确金额。 |
received_amount | 链上实际到账金额。 |
address | 收款地址或钱包地址。 |
timestamp | 回调生成时的 Unix 秒级时间戳。 |
tx_hash | 链上交易哈希,未检测到交易时可能为空。 |
| 状态 | 含义 | 建议处理 |
|---|---|---|
pending | 等待用户付款 | 继续展示收银台,不发货 |
confirming | 已检测到账,等待链上确认数达标 | 等待 Webhook 或查询变为 paid |
paid | 支付成功 | 可以按业务规则发货或开通服务 |
expired | 订单已过期 | 让用户重新创建订单 |
underpaid | 少付 | 人工核对或联系用户补差额 |
overpaid | 多付 | 人工核对,多余金额按你的规则处理 |
manual_review | 需要人工处理 | 查看链上交易和工单后处理 |
cancelled | 订单已取消 | 不再接受该订单支付 |
按开发语言切换
$body = json_encode($payload, JSON_UNESCAPED_SLASHES);
$timestamp = time();
$nonce = bin2hex(random_bytes(12));
$canonical = 'POST|/api/v1/payments|' . $timestamp . '|' . $nonce . '|' . hash('sha256', $body);
$signature = hash_hmac('sha256', $canonical, $apiSecret);
const crypto = require('crypto');
const body = JSON.stringify(payload);
const timestamp = Math.floor(Date.now() / 1000).toString();
const nonce = crypto.randomBytes(12).toString('hex');
const bodyHash = crypto.createHash('sha256').update(body).digest('hex');
const canonical = `POST|/api/v1/payments|${timestamp}|${nonce}|${bodyHash}`;
const signature = crypto.createHmac('sha256', apiSecret).update(canonical).digest('hex');
import hashlib, hmac, json, secrets, time
body = json.dumps(payload, separators=(',', ':'), ensure_ascii=False)
timestamp = str(int(time.time()))
nonce = secrets.token_hex(12)
body_hash = hashlib.sha256(body.encode()).hexdigest()
canonical = f"POST|/api/v1/payments|{timestamp}|{nonce}|{body_hash}"
signature = hmac.new(api_secret.encode(), canonical.encode(), hashlib.sha256).hexdigest()
String bodyHash = sha256Hex(body);
String canonical = "POST|/api/v1/payments|" + timestamp + "|" + nonce + "|" + bodyHash;
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(apiSecret.getBytes(StandardCharsets.UTF_8), "HmacSHA256"));
String signature = HexFormat.of().formatHex(mac.doFinal(canonical.getBytes(StandardCharsets.UTF_8)));
bodyHash := sha256.Sum256(body)
canonical := fmt.Sprintf("POST|/api/v1/payments|%s|%s|%x", timestamp, nonce, bodyHash)
mac := hmac.New(sha256.New, []byte(apiSecret))
mac.Write([]byte(canonical))
signature := hex.EncodeToString(mac.Sum(nil))
查看 Webhook 推送状态、响应码和重试情况。
| 事件 ID | 支付订单 | 站点 | 事件类型 | 目标地址 | 状态 | 响应码 | 次数 | 下次重试 | 送达时间 | 创建时间 | 响应内容 | 操作 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| {{w.event_id}} | {{w.payment_id||'-'}} {{w.merchant_order_no||w.subject||'-'}} | {{w.site_name}} | {{w.event_type}} | {{w.target_url}} | {{webhookStatusText(w.status)}} | {{w.response_status||'-'}} | {{w.attempt_count}} | {{fmt(w.next_attempt_at)}} | {{fmt(w.delivered_at)}} | {{fmt(w.created_at)}} | {{w.response_body||'-'}} | - |
| 暂无回调记录 | ||||||||||||
适合没有后端签名能力的页面,复制链接或嵌入代码即可发起固定金额付款。
管理个人资料和登录安全
| 时间 | IP 地址 | 结果 | 设备 |
|---|---|---|---|
| {{fmt(r.created_at)}} | {{r.ip_address}} | {{r.successful==1?'成功':'失败'}} | {{r.user_agent}} |
| 暂无登录记录 | |||
选择站点可用的钱包。用户支付时可在这些钱包之间切换,历史订单保留当时选择的钱包快照。
以下为当前密钥,可在站点列表再次查看。
{{secret.api_key||'保持不变'}}{{secret.api_secret}}{{secret.webhook_secret}}打开钱包 App 扫码,选择 USDT-TRC20 转账