您的第一笔支付
一个完整的逐步教程,用于创建和处理您的第一笔 HashNut 支付。
概述
在本教程中,您将:
- 设置您的开发环境
- 创建支付订单
- 处理支付
- 处理 Webhook 通知
时间: ~15 分钟
难度: 初级
前置要求
- ✅ 安装 已完成
- ✅ 从 HashNut 控制台获取的 API 凭证
- ✅ 带有测试代币的测试钱包
- ✅ 开发环境已设置
步骤 1: 初始化客户端
- JavaScript/TypeScript
- Python
- Java
import { HashnutClient } from '@hashnut/sdk';
const client = new HashnutClient({
baseUrl: 'https://testnet.hashnut.io',
accessKeyId: process.env.HASHNUT_ACCESS_KEY_ID!,
apiKey: process.env.HASHNUT_API_KEY!,
});
from hashnut import HashnutClient
client = HashnutClient(
base_url='https://testnet.hashnut.io',
access_key_id=os.getenv('HASHNUT_ACCESS_KEY_ID'),
api_key=os.getenv('HASHNUT_API_KEY')
)
import io.hashnut.HashnutClient;
HashnutClient client = new HashnutClient(
"https://testnet.hashnut.io",
System.getenv("HASHNUT_ACCESS_KEY_ID"),
System.getenv("HASHNUT_API_KEY")
);
步骤 2: 创建支付订单
- JavaScript/TypeScript
- Python
- Java
// 创建订单
const order = await client.orders.create({
merchantOrderId: `order-${Date.now()}`,
chainCode: 'erc20',
coinCode: 'usdt',
amount: 0.01,
callBackUrl: 'https://your-site.com/api/webhook',
frontendCallbackUrl: 'https://your-site.com/payment/success',
});
console.log('Order created:', order.payOrderId);
console.log('Payment URL:', order.paymentUrl);
import time
# 创建订单
order = client.orders.create(
merchant_order_id=f'order-{int(time.time())}',
chain_code='erc20',
coin_code='usdt',
amount=0.01,
callback_url='https://your-site.com/api/webhook',
frontend_callback_url='https://your-site.com/payment/success'
)
print(f'Order created: {order.pay_order_id}')
print(f'Payment URL: {order.payment_url}')
// 创建订单
CreateOrderRequest request = CreateOrderRequest.builder()
.merchantOrderId("order-" + System.currentTimeMillis())
.chainCode("erc20")
.coinCode("usdt")
.amount(new BigDecimal("0.01"))
.callBackUrl("https://your-site.com/api/webhook")
.frontendCallbackUrl("https://your-site.com/payment/success")
.build();
Order order = client.orders().create(request);
System.out.println("Order created: " + order.getPayOrderId());
System.out.println("Payment URL: " + order.getPaymentUrl());
步骤 3: 重定向客户到支付页面
// 在您的前端
window.location.href = order.paymentUrl;
或在 React 组件中:
<button onClick={() => window.open(order.paymentUrl, '_blank')}>
Pay Now
</button>
步骤 4: 客户完成支付
客户将:
- 看到带有订单详情的支付页面
- 连接他们的钱包
- 批准支付交易
- 等待区块链确认
步骤 5: 处理 Webhook 通知
- JavaScript/TypeScript
- Python
- Java
// Express.js webhook 端点
import express from 'express';
const app = express();
app.post('/api/webhook', express.raw({ type: 'application/json' }), async (req, res) => {
try {
// 验证 webhook 签名
const isValid = client.webhooks.verify(req);
if (!isValid) {
return res.status(401).send('Invalid signature');
}
// 解析 webhook 数据
const data = JSON.parse(req.body.toString());
const { payOrderId, merchantOrderId, state } = data;
// 查询订单状态以获取最新详情
const order = await client.orders.query({
payOrderId,
merchantOrderId,
accessSign: data.accessSign,
});
// 处理支付成功
if (order.state === 4) {
console.log('Payment successful!');
// 更新您的数据库
await updateOrderStatus(merchantOrderId, 'paid');
// 履行订单
await fulfillOrder(merchantOrderId);
}
res.send('success');
} catch (error) {
console.error('Webhook error:', error);
res.status(500).send('failed');
}
});
# Flask webhook 端点
from flask import Flask, request
@app.route('/api/webhook', methods=['POST'])
def webhook():
try:
# 验证 webhook 签名
if not client.webhooks.verify(request):
return 'Invalid signature', 401
# 解析 webhook 数据
data = request.get_json()
pay_order_id = data['payOrderId']
merchant_order_id = data['merchantOrderId']
state = data['state']
# 查询订单状态
order = client.orders.query(
pay_order_id=pay_order_id,
merchant_order_id=merchant_order_id,
access_sign=data['accessSign']
)
# 处理支付成功
if order.state == 4:
print('Payment successful!')
# 更新数据库
update_order_status(merchant_order_id, 'paid')
# 履行订单
fulfill_order(merchant_order_id)
return 'success'
except Exception as e:
print(f'Webhook error: {e}')
return 'failed', 500
// Spring Boot webhook 端点
@PostMapping("/api/webhook")
public ResponseEntity<String> webhook(@RequestBody WebhookPayload payload) {
try {
// 验证 webhook 签名
if (!client.webhooks().verify(payload)) {
return ResponseEntity.status(401).body("Invalid signature");
}
// 查询订单状态
Order order = client.orders().query(
payload.getPayOrderId(),
payload.getMerchantOrderId(),
payload.getAccessSign()
);
// 处理支付成功
if (order.getState() == 4) {
System.out.println("Payment successful!");
// 更新数据库
orderService.updateStatus(payload.getMerchantOrderId(), "paid");
// 履行订单
orderService.fulfill(payload.getMerchantOrderId());
}
return ResponseEntity.ok("success");
} catch (Exception e) {
System.err.println("Webhook error: " + e.getMessage());
return ResponseEntity.status(500).body("failed");
}
}
步骤 6: 测试完整流程
本地测试设置
- 使用 ngrok 进行本地 webhook 测试:
# 安装 ngrok
npm install -g ngrok
# 暴露本地服务器
ngrok http 3000
# 使用 HTTPS URL 作为您的 webhook URL
# https://abc123.ngrok.io/api/webhook
- 创建测试订单:
const order = await client.orders.create({
merchantOrderId: 'test-order-1',
chainCode: 'erc20',
coinCode: 'usdt',
amount: 0.01,
callBackUrl: 'https://your-ngrok-url.ngrok.io/api/webhook',
frontendCallbackUrl: 'http://localhost:3000/payment/success',
});
-
完成支付:
- 打开支付 URL
- 连接钱包
- 使用测试代币完成支付
-
验证 webhook:
- 检查您的服务器日志
- 验证订单状态已更新
- 确认支付已处理
完整示例
这是一个完整的工作示例:
- JavaScript/TypeScript
- Python
import express from 'express';
import { HashnutClient } from '@hashnut/sdk';
const app = express();
app.use(express.json());
const client = new HashnutClient({
baseUrl: 'https://testnet.hashnut.io',
accessKeyId: process.env.HASHNUT_ACCESS_KEY_ID!,
apiKey: process.env.HASHNUT_API_KEY!,
});
// 创建订单端点
app.post('/api/create-order', async (req, res) => {
try {
const order = await client.orders.create({
merchantOrderId: `order-${Date.now()}`,
chainCode: 'erc20',
coinCode: 'usdt',
amount: 0.01,
callBackUrl: `${process.env.WEBHOOK_URL}/api/webhook`,
frontendCallbackUrl: `${process.env.FRONTEND_URL}/payment/success`,
});
res.json({ paymentUrl: order.paymentUrl });
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// Webhook 端点
app.post('/api/webhook', express.raw({ type: 'application/json' }), async (req, res) => {
try {
if (!client.webhooks.verify(req)) {
return res.status(401).send('Invalid signature');
}
const data = JSON.parse(req.body.toString());
const order = await client.orders.query({
payOrderId: data.payOrderId,
merchantOrderId: data.merchantOrderId,
accessSign: data.accessSign,
});
if (order.state === 4) {
// 支付成功 - 更新您的数据库
console.log('Payment successful:', order.payOrderId);
}
res.send('success');
} catch (error) {
console.error('Webhook error:', error);
res.status(500).send('failed');
}
});
app.listen(3000, () => {
console.log('Server running on http://localhost:3000');
});
from flask import Flask, request, jsonify
from hashnut import HashnutClient
import os
app = Flask(__name__)
client = HashnutClient(
base_url='https://testnet.hashnut.io',
access_key_id=os.getenv('HASHNUT_ACCESS_KEY_ID'),
api_key=os.getenv('HASHNUT_API_KEY')
)
# 创建订单端点
@app.route('/api/create-order', methods=['POST'])
def create_order():
try:
order = client.orders.create(
merchant_order_id=f'order-{int(time.time())}',
chain_code='erc20',
coin_code='usdt',
amount=0.01,
callback_url=f'{os.getenv("WEBHOOK_URL")}/api/webhook',
frontend_callback_url=f'{os.getenv("FRONTEND_URL")}/payment/success'
)
return jsonify({'payment_url': order.payment_url})
except Exception as e:
return jsonify({'error': str(e)}), 500
# Webhook 端点
@app.route('/api/webhook', methods=['POST'])
def webhook():
try:
if not client.webhooks.verify(request):
return 'Invalid signature', 401
data = request.get_json()
order = client.orders.query(
pay_order_id=data['payOrderId'],
merchant_order_id=data['merchantOrderId'],
access_sign=data['accessSign']
)
if order.state == 4:
print(f'Payment successful: {order.pay_order_id}')
return 'success'
except Exception as e:
print(f'Webhook error: {e}')
return 'failed', 500
if __name__ == '__main__':
app.run(port=3000)
故障排除
常见问题
问题: "Invalid signature"
- ✅ 检查
apiKey是否正确 - ✅ 验证请求体是否正确字符串化
- ✅ 确保所有必需的标头都存在
问题: "Order not found"
- ✅ 验证
payOrderId和merchantOrderId是否正确 - ✅ 检查您是否使用正确的环境 (测试 网 vs 生产环境)
问题: 未收到 Webhook
- ✅ 检查 webhook URL 是否可访问 (使用 ngrok 进行本地测试)
- ✅ 验证 webhook URL 使用 HTTPS
- ✅ 检查服务器日志中的错误
下一步
- 订单管理: 学习高级订单功能
- Webhook 集成: 深入了解 webhooks
- 错误处理: 优雅地处理错误
恭喜! 🎉 您已创建了您的第一笔 HashNut 支付。探索 完整文档 以解锁更多功能!