订单端点
通过 HashNut API 创建和管理支付订单。
创建支付订单
创建新的支付订单并返回支付详情,包括支付 URL。
端点:POST /api/v3.0.0/pay/createPayOrderOnSplitWalletWithApiKey
请求
请求头:
hashnut-request-uuid: <uuid>
hashnut-request-timestamp: <timestamp>
hashnut-request-sign: <signature>
Content-Type: application/json
请求体:
{
"accessKeyId": "string",
"merchantOrderId": "string",
"chainCode": "string",
"coinCode": "string",
"amount": 0.01,
"callBackUrl": "string",
"frontendCallbackUrl": "string",
"receiptAddress": "string",
"splitterAddress": "string"
}
请求参数
| 参数 | 类型 | 必填 | 描述 |
|---|---|---|---|
accessKeyId | string | ✅ 是 | 您的商户访问密钥 ID |
merchantOrderId | string | ✅ 是 | 唯一商户订单 ID(最多 255 个字符,每个商户必须唯一) |
chainCode | string | ✅ 是 | 链代码。支持的值:"erc20"、"bsc-erc20"、"polygon-erc20"、"tron-trc20" |
coinCode | string | ✅ 是 | 货币代码(例如,"usdt"、"usdc"、"MockUSDT")- 区分大小写 |
amount | decimal | ✅ 是 | 基础单位的支付金额(例如,0.01 表示 0.01 USDT)。最小值:0.01。四舍五入到 2 位小数。 |
callBackUrl | string | ⚠️ 可选 | 用于支付状态更新的后端 webhook URL |
frontendCallbackUrl | string | ⚠️ 可选 | 支付完成后的前端重定向 URL |
receiptAddress | string | ⚠️ 可选 | 自定义商户接收地址。必须匹配格式:EVM (0x...) 或 TRON (T...)。如果未提供,则使用账户的默认地址。 |
splitterAddress | string | ⚠️ 可选 | 分账合约地址(用于接收支付的智能合约)。必须是 EVM 格式 (0x...)。 |
响应
成功响应(200 OK):
{
"code": 0,
"msg": "success",
"data": {
"payOrderId": "01KBZ292SK2GKFK97916F5EC3B",
"accessSign": "D3DE7E4002057C0EAED1BE2268DA53CC9058DCFC9DCAF50D999AF270A7B033C5",
"merchantOrderId": "e30ff306-5552-497d-9083-fd6e943dfd73"
}
}
响应字段
| 字段 | 类型 | 描述 |
|---|---|---|
payOrderId | string | HashNut 平台订单 ID(唯一标识符) |
accessSign | string | 用于查询订单状态的访问签名 |
merchantOrderId | string | 商户订单 ID 的回显 |
支付 URL 构造
收到响应后,构造支付 URL:
https://testnet.hashnut.io/pay?accessSign={accessSign}&merchantOrderId={merchantOrderId}&payOrderId={payOrderId}&chainCode={chainCode}
示例:
https://testnet.hashnut.io/pay?accessSign=D3DE7E4002057C0EAED1BE2268DA53CC9058DCFC9DCAF50D999AF270A7B033C5&merchantOrderId=e30ff306-5552-497d-9083-fd6e943dfd73&payOrderId=01KBZ292SK2GKFK97916F5EC3B&chainCode=erc20
错误响应
签名无效(401):
{
"code": -2,
"msg": "Invalid signature or credentials",
"data": null
}
参数无效(400):
{
"code": -2,
"msg": "Invalid parameters",
"data": null
}
常见错误:
-2:认证/签名错误、凭据无效或缺少必需字段- 其他代码:参见错误代码
代码示例
- JavaScript
- Python
- cURL
const response = await fetch(
'https://testnet.hashnut.io/api/v3.0.0/pay/createPayOrderOnSplitWalletWithApiKey',
{
method: 'POST',
headers: {
'hashnut-request-uuid': uuid,
'hashnut-request-timestamp': timestamp,
'hashnut-request-sign': signature,
'Content-Type': 'application/json'
},
body: JSON.stringify({
accessKeyId: 'YOUR_ACCESS_KEY_ID',
merchantOrderId: `order-${Date.now()}`,
chainCode: 'erc20',
coinCode: 'usdt',
amount: 0.01,
callBackUrl: 'https://your-site.com/webhook',
frontendCallbackUrl: 'https://your-site.com/payment/success'
})
}
);
const result = await response.json();
if (result.code === 0) {
const paymentUrl = `https://testnet.hashnut.io/pay?accessSign=${result.data.accessSign}&merchantOrderId=${result.data.merchantOrderId}&payOrderId=${result.data.payOrderId}&chainCode=erc20`;
console.log('Payment URL:', paymentUrl);
}
import requests
response = requests.post(
'https://testnet.hashnut.io/api/v3.0.0/pay/createPayOrderOnSplitWalletWithApiKey',
headers={
'hashnut-request-uuid': uuid,
'hashnut-request-timestamp': timestamp,
'hashnut-request-sign': signature,
'Content-Type': 'application/json'
},
json={
'accessKeyId': 'YOUR_ACCESS_KEY_ID',
'merchantOrderId': f'order-{int(time.time())}',
'chainCode': 'erc20',
'coinCode': 'usdt',
'amount': 0.01,
'callBackUrl': 'https://your-site.com/webhook',
'frontendCallbackUrl': 'https://your-site.com/payment/success'
}
)
result = response.json()
if result['code'] == 0:
payment_url = f"https://testnet.hashnut.io/pay?accessSign={result['data']['accessSign']}&merchantOrderId={result['data']['merchantOrderId']}&payOrderId={result['data']['payOrderId']}&chainCode=erc20"
print(f'Payment URL: {payment_url}')
curl -X POST 'https://testnet.hashnut.io/api/v3.0.0/pay/createPayOrderOnSplitWalletWithApiKey' \
-H 'hashnut-request-uuid: 550e8400-e29b-41d4-a716-446655440000' \
-H 'hashnut-request-timestamp: 1704067200000' \
-H 'hashnut-request-sign: <your-signature>' \
-H 'Content-Type: application/json' \
-d '{
"accessKeyId": "YOUR_ACCESS_KEY_ID",
"merchantOrderId": "order-123",
"chainCode": "erc20",
"coinCode": "usdt",
"amount": 0.01,
"callBackUrl": "https://your-site.com/webhook",
"frontendCallbackUrl": "https://your-site.com/payment/success"
}'
查询支付订单状态
使用访问签名查询支付订单的当前状态。
端点:POST /api/v3.0.0/pay/queryPayOrderWithAccessSign
请求
请求头:
Content-Type: application/json
注意:此端点不需要签名认证(使用 accessSign 代替)。
请求体:
{
"merchantOrderId": "string",
"payOrderId": "string",
"accessSign": "string"
}
请求参数
| 参数 | 类型 | 必填 | 描述 |
|---|---|---|---|
merchantOrderId | string | ✅ 是 | 您的商户订单 ID |
payOrderId | string | ✅ 是 | HashNut 平台订单 ID |
accessSign | string | ✅ 是 | 来自创建订单响应的访问签名 |
响应
成功响应(200 OK):
{
"code": 0,
"msg": "success",
"data": {
"merchantAddress": "0x1234...",
"chain": "Ethereum",
"chainCode": "erc20",
"coinCode": "usdt",
"createChannel": 0,
"accessChannel": 0,
"merchantOrderId": "e30ff306-5552-497d-9083-fd6e943dfd73",
"payOrderId": "01KBZ292SK2GKFK97916F5EC3B",
"tokenAddress": "0xdAC17F958D2ee523a2206206994597C13D831ec7",
"receiptAddress": "0x5678...",
"amount": 0.01,
"state": 4,
"accessSign": "D3DE7E4002057C0EAED1BE2268DA53CC9058DCFC9DCAF50D999AF270A7B033C5",
"payTxId": "0xabcdef1234567890...",
"confirmCount": "12",
"walletConnectEnable": true,
"bridgeServerAddress": "https://bridge.hashnut.io",
"eip712ChainId": "1",
"chainId": "1",
"callBackUrl": "https://merchant.com/api/payment/webhook",
"createTime": "2024-01-01T00:00:00Z",
"rate": 1.0,
"obtainAmount": 0.01,
"platformFee": 0
}
}
响应字段
| 字段 | 类型 | 描述 |
|---|---|---|
merchantAddress | string | 商户钱包地址 |
chain | string | 链名称(例如,"Ethereum"、"BSC") |
chainCode | string | 链代码(例如,"erc20") |
coinCode | string | 货币代码(例如,"usdt") |
merchantOrderId | string | 商户订单 ID |
payOrderId | string | HashNut 平台订单 ID |
tokenAddress | string | 代币合约地址 |
receiptAddress | string | 接收地址 |
amount | decimal | 支付金额 |
state | integer | 订单状态(参见订单状态) |
accessSign | string | 访问签名 |
payTxId | string | 交易哈希(如果已支付) |
confirmCount | string | 确认数 |
walletConnectEnable | boolean | 是否启用 WalletConnect |
bridgeServerAddress | string | 桥接服务器地址 |
eip712ChainId | string | EIP-712 链 ID |
chainId | string | 链 ID |
callBackUrl | string | Webhook 回调 URL |
createTime | string | 创建时间戳(ISO 格式) |
rate | decimal | 汇率(如适用) |
obtainAmount | decimal | 商户获得的金额 |
platformFee | decimal | 平台费用 |
订单状态
| 状态 | 代码 | 描述 |
|---|---|---|
| 未支付 | 0 | 订单已创建,等待支付 |
| 未完成 | 1 | 支付已发起但未完成 |
| 等待确认 | 2 | 交易已广播,等待确认 |
| 确认中 | 3 | 交易已确认,验证支付中 |
| 成功 | 4 | 支付完成并已验证 |
| 失败 | -1 | 支付交易失败 |
| 已过期 | -2 | 订单已过期未支付 |
| 已取消 | -3 | 订单已被商户取消 |
参见订单状态了解详细信息。
代码示例
- JavaScript
- Python
- cURL
const response = await fetch(
'https://testnet.hashnut.io/api/v3.0.0/pay/queryPayOrderWithAccessSign',
{
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
merchantOrderId: 'order-123',
payOrderId: '01KBZ292SK2GKFK97916F5EC3B',
accessSign: 'D3DE7E4002057C0EAED1BE2268DA53CC9058DCFC9DCAF50D999AF270A7B033C5'
})
}
);
const result = await response.json();
if (result.code === 0) {
const order = result.data;
console.log('Order State:', order.state);
console.log('Amount:', order.amount);
if (order.state === 4) {
console.log('Payment successful!');
}
}
import requests
response = requests.post(
'https://testnet.hashnut.io/api/v3.0.0/pay/queryPayOrderWithAccessSign',
headers={'Content-Type': 'application/json'},
json={
'merchantOrderId': 'order-123',
'payOrderId': '01KBZ292SK2GKFK97916F5EC3B',
'accessSign': 'D3DE7E4002057C0EAED1BE2268DA53CC9058DCFC9DCAF50D999AF270A7B033C5'
}
)
result = response.json()
if result['code'] == 0:
order = result['data']
print(f"Order State: {order['state']}")
print(f"Amount: {order['amount']}")
if order['state'] == 4:
print('Payment successful!')
curl -X POST 'https://testnet.hashnut.io/api/v3.0.0/pay/queryPayOrderWithAccessSign' \
-H 'Content-Type: application/json' \
-d '{
"merchantOrderId": "order-123",
"payOrderId": "01KBZ292SK2GKFK97916F5EC3B",
"accessSign": "D3DE7E4002057C0EAED1BE2268DA53CC9058DCFC9DCAF50D999AF270A7B033C5"
}'
最佳实践
- Webhook 后始终查询:即使收到 webhook,也要查询订单状态以获取最新状态
- 处理所有状态:实现对所有订单状态的处理,特别是终端状态(成功、失败、过期、取消)
- 轮询:如果不使用 webhook,定期轮询订单状态(但不要太频繁)
- 错误处理:在处理数据之前始终检查
response.code === 0 - 幂等性:使用
merchantOrderId确保订单唯一性并防止重复
下一步
准备创建订单? 查看快速开始 →