你的首笔支付
逐步引导你创建并处理首笔 Pelago 支付。
实现目标
一个完整的支付流程,涵盖:
- 创建支付请求
- 向客户展示二维码
- 处理支付 Webhook
- 确认支付成功
前提条件
完整示例:Express.js 支付服务器
import express from 'express';
import { PelagoClient } from '@pelago/sdk';
const app = express();
app.use(express.json());
// 初始化 Pelago 客户端
const pelago = new PelagoClient({
apiKey: process.env.PELAGO_API_KEY!,
apiSecret: process.env.PELAGO_API_SECRET!,
environment: 'sandbox'
});
// 存储待处理订单(生产环境请使用数据库)
const orders = new Map<string, { status: string; amount: number }>();
// 1. 创建新订单和支付
app.post('/api/checkout', async (req, res) => {
const { productId, email } = req.body;
// 创建订单
const orderId = `order_${Date.now()}`;
const amount = 25.00; // 商品价格
orders.set(orderId, { status: 'pending', amount });
try {
// 创建 Pelago 支付
const payment = await pelago.payments.create({
amount,
currency: 'USD',
cryptocurrency: 'USDC',
network: 'stellar-testnet',
merchantWallet: process.env.MERCHANT_WALLET!,
redirectUrl: `${process.env.APP_URL}/order/${orderId}/success`,
webhookUrl: `${process.env.APP_URL}/api/webhook`,
metadata: {
orderId,
customerEmail: email,
productId
}
});
res.json({
orderId,
paymentId: payment.id,
paymentUrl: payment.url,
qrCode: payment.qrCode,
expiresAt: payment.expiresAt
});
} catch (error) {
console.error('支付创建失败:', error);
res.status(500).json({ error: 'Failed to create payment' });
}
});
// 2. 查询支付/订单状态
app.get('/api/orders/:orderId', (req, res) => {
const order = orders.get(req.params.orderId);
if (!order) {
return res.status(404).json({ error: 'Order not found' });
}
res.json(order);
});
// 3. 处理 Pelago Webhook
app.post('/api/webhook', async (req, res) => {
const signature = req.headers['x-pelago-signature'] as string;
// 验证 Webhook 签名
if (!pelago.webhooks.verify(req.body, signature)) {
console.warn('无效的 Webhook 签名');
return res.status(401).json({ error: 'Invalid signature' });
}
const event = req.body;
const { orderId } = event.data.metadata;
console.log(`收到 Webhook: ${event.type},订单 ${orderId}`);
switch (event.type) {
case 'payment.completed':
// 更新订单状态
const order = orders.get(orderId);
if (order) {
order.status = 'paid';
orders.set(orderId, order);
}
// 触发履约(发送邮件、发货等)
console.log(`✅ 订单 ${orderId} 支付成功!`);
break;
case 'payment.failed':
const failedOrder = orders.get(orderId);
if (failedOrder) {
failedOrder.status = 'failed';
orders.set(orderId, failedOrder);
}
console.log(`❌ 订单 ${orderId} 支付失败`);
break;
case 'payment.expired':
const expiredOrder = orders.get(orderId);
if (expiredOrder) {
expiredOrder.status = 'expired';
orders.set(orderId, expiredOrder);
}
console.log(`⏱️ 订单 ${orderId} 支付已过期`);
break;
}
// 始终返回 200 以确认收到
res.status(200).json({ received: true });
});
// 启动服务器
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`服务器运行在端口 ${PORT}`);
});
测试你的集成
1. 启动服务器
# 设置环境变量
export PELAGO_API_KEY=test_pk_xxxxx
export PELAGO_API_SECRET=test_sk_xxxxx
export MERCHANT_WALLET=GXXXXX...
export APP_URL=https://your-ngrok-url.ngrok.io
# 启动服务器
npx ts-node server.ts
2. 使用 ngrok 暴露 Webhook
ngrok http 3000
# 复制生成的 https:// URL
3. 创建测试订单
curl -X POST http://localhost:3000/api/checkout \
-H "Content-Type: application/json" \
-d '{"productId": "prod_123", "email": "[email protected]"}'
响应:
{
"orderId": "order_1707401234567",
"paymentId": "pay_abc123",
"paymentUrl": "https://pay.sandbox.pelago.tech/pay_abc123",
"qrCode": "data:image/png;base64,...",
"expiresAt": "2025-02-08T22:30:00Z"
}
4. 完成支付
- 在浏览器中打开
paymentUrl - 连接你的测试钱包
- 批准测试 USDC 转账
- 观察 Webhook 接收到
payment.completed事件
5. 验证订单状态
curl http://localhost:3000/api/orders/order_1707401234567
{
"status": "paid",
"amount": 25.00
}
支付流程可视化
常见问题
Webhook 未收到
- 确保 Webhook URL 可被公网访问
- 检查 ngrok 日志中的传入请求
- 验证 Webhook URL 没有拼写错误
支付创建失败
- 检查 API 密钥环境变量
- 验证钱包地址格式
- 确保使用了正确的网络
签名验证失败
- 使用原始请求体(未解析的)
- 确保
x-pelago-signature请求头存在 - 向验证函数传入正确的 API Secret
下一步
完成首笔支付后: