订单履约
在用户完成支付后,您的系统需要接收确认信号并交付商品或服务(即“履约”)。
由于区块链交易的异步特性,前端的跳转(Redirect)并不能作为支付成功的最终依据。Webhook 是确认支付状态并进行订单履约的唯一权威方式。
履约流程概览
GStable 的结算速度极快(通常在 30-40 秒内),因此我们建议采用以下标准的履约逻辑:
- 监听 Webhook:在您的服务器上配置一个端点接收 POST 请求。
- 验证签名:确保请求来自 GStable,防止伪造。
- 检查状态:根据事件类型(
paid或completed)决定履约时机。 - 执行业务逻辑:在数据库中更新订单状态、发送邮件或发放权益。
核心事件状态
在 Checkout 流程中,您主要需要关注 session 相关的生命周期事件。
1. 支付成功 (session.paid)
- 触发时机:用户已在链上完成转账,且交易已被区块链确认。
- 资金状态:资金已从用户钱包转出,正在进行跨链路由或归集。
- 建议动作:
- 锁定库存:防止超卖。
- 即时交付:对于低风险的数字商品(如游戏道具、电子书),可在此阶段提前履约,无需等待资金最终入账。
2. 结算完成 (session.completed)
- 触发时机:资金已成功到达商户配置的收款钱包地址。
- 资金状态:落袋为安。交易流程彻底结束。
- 建议动作:
- 高价值履约:对于发货实物、大额充值等场景,建议等待此事件。
- 财务对账:将此作为收入确认的依据。
结算速度
得益于我们的无资金池全链支付架构,从 session.paid 到 session.completed 通常仅需 30 至 40 秒。
Webhook 数据结构
当事件触发时,您的服务器将收到包含以下 JSON 结构的 POST 请求。
Payload 中的数据结构与 查询支付会话 接口返回的数据完全一致。
示例:结算完成事件 (session.completed)
{
"eventId": "evt_i4NWz4J3QkWugyq1",
"eventType": "session.completed",
"businessType": "session",
"occurrence": "2026-01-04 02:52:38",
"isSubscribable": true,
"payload": {
// --- 会话详情 (对应 API 响应中的 session 对象) ---
"sessionData": {
"sessionId": "sess_example_payment_01",
"sessionType": "chk",
"businessId": "",
"businessType": "",
"clientCode": "clt_l8ZBnpOSV9pVlaLK0dP5jsq5NzfqN3Vc",
"payer": "0xUserWalletAddress...", // 付款人钱包地址
"payerEmail": "user@example.com",
"payerEmailRequired": 1,
"paidToken": "0xTokenAddress...", // 用户实际支付的代币合约
"receiptId": "rcpt_txUdSs2ASditQhrr",
"recipient": "0xMerchantWalletAddress...",
"settlementToken": "polygon::usdc",
"feeModel": 1,
"amount": 15000000, // 订单金额 (Micro-USD)
"lineItems": {
"items": [
{
"lineItemId": "li_example_item_03",
"itemType": "product",
"quantity": 1,
"unitPrice": 10000000,
"productData": { "productName": "高级会员" }
}
// ...
]
},
"expirationTime": 1767343946,
"successUrl": "https://yoursite.com/order/success",
"paymentUrl": "https://pay.gstable.io/checkout/sess_...",
"signedOnce": 1,
"initiateTx": "0xSourceTxHash...",
"completeTx": "0xTargetTxHash...",
"paymentSucceededTime": "2025-12-25 07:26:35",
"settlementSucceededTime": "2025-12-25 07:27:10",
"createAt": "2026-01-02 07:52:26",
"status": "completed",
"metadata": {
"internalOrderId": "ord_8823_xyz"
}
},
// --- 交易详情 (对应 API 响应中的 transaction 对象) ---
"transaction": {
"orderId": "0x8a7f...",
"channelId": "da1e3483",
"orderType": 7106155,
"from": "0xUserWalletAddress...",
"to": "0xPlatformContractAddress...",
"metaData": "0x",
"totalValue": 15000000, // 用户支付总额
"paymentValue": 15000000, // 订单面额
"feeValue": 30000, // 手续费 (Micro-USD)
"netValue": 14970000, // 商户实收净额 (Micro-USD)
"sourceTx": "0xSourceTxHash...",
"targetTx": "0xTargetTxHash...",
"executeTime": "2025-12-25 07:26:35",
"finalizeTime": "2025-12-25 07:26:35"
}
}
}
关键字段解析
eventId: 事件的全局唯一标识符。建议用于幂等性处理(即如果收到相同的eventId,则忽略处理,防止重复发货)。payload.sessionData.metadata: 您在创建 Session 时传入的自定义数据。这是将 Webhook 通知与您本地数据库中的订单(internalOrderId)进行关联的关键。payload.transaction.netValue: 商户实际到账金额(Micro-USD)。财务对账时请以此字段为准。
安全与处理
为了确保资金安全,您必须在服务器端验证所有 Webhook 请求的签名。
1. 验证签名
GStable 会在请求 Header 中包含 x-gstable-signature。您需要使用 Dashboard 中获取的 Signing Secret 计算 HMAC-SHA256 签名并进行比对。
2. 幂等性处理
网络波动可能导致 Webhook 重试。请务必记录已处理过的 eventId。
伪代码示例:处理履约
app.post('/webhook', (req, res) => {
// 1. 验证签名 (参考 Webhook 开发文档)
verifySignature(req);
const event = req.body;
// 2. 幂等性检查
if (isEventProcessed(event.eventId)) {
return res.send({ received: true });
}
// 3. 处理业务逻辑
if (event.eventType === 'session.completed') {
const session = event.payload.sessionData;
const transaction = event.payload.transaction;
const orderId = session.metadata.internalOrderId;
const receivedAmount = transaction.netValue; // 实收金额
// 执行履约:更新数据库,发货
fulfillOrder(orderId, receivedAmount);
}
// 4. 记录事件已处理
recordEvent(event.eventId);
res.send({ received: true });
});
开发指南
关于详细的验签代码实现(Node.js, Python, Go 等)以及完整的事件类型列表,请参阅专门的 Webhook 开发文档。
总结
至此,您已经完成了 Checkout 的集成!
- 您通过 API 创建了支付会话。
- 用户在托管页面完成了支付。
- 您的服务器通过 Webhook 确认了收款并完成了订单履约。
现在,您可以前往 Dashboard 查看交易数据,或继续探索更多高级功能。