生产运营
安全处理 notify、恢复、终局验证、对账、密钥轮换和支付事件。
生产支付体验不能只依赖一次成功的 pay() 响应。履约逻辑必须能处理超时、重复请求、延迟确认和 webhook 丢失。
证据优先级
| 证据 | 正确用途 | 不能用于 |
|---|---|---|
| 付款客户端结果 | 即时 UX 和上传证据 | 单独触发不可逆履约 |
| Notify 事件 | 快速唤醒后端验证器 | 财务终局性 |
| Signed receipt | 验证网关输出并绑定上下文 | 取代链上验证 |
| 链状态 | 确认转账和终局性 | 商户订单语义 |
| 商户数据库 | 幂等履约与业务策略 | 在没有证据时声明转账 |
恢复丢失的成功响应
TypeScriptimport { recoverSettlement } from 'x402-paysdk/pay';const recovered = await recoverSettlement({ gateway: 'https://pay.example.com', refId, paymentPayload, txHash, signedOffer});if (recovered.recovered) { await submitEvidence(recovered.txHash, recovered.signedReceipt, recovered.receipt);}
恢复只检查链上证据并尝试重建收据,不会再次调用 /settle。原始 payment payload 属于可重放敏感数据,只能在必要的最短时间内保存,且绝不能进入日志。
从链历史对账
TypeScriptimport { reconcile } from 'x402-paysdk/merchant';const report = await reconcile(merchant, { payTo, fromBlock: lastReconciledBlock, limit: 200, receipts: archivedPaymentReceipts, refundReceipts: archivedRefundReceipts, minConfirmations: 3, verifyChain: true});for (const anomaly of report.anomalies) { await incidentQueue.enqueue(anomaly);}
只有在报告和业务更新都完成持久化后,才能把 checkpoint 推进到 report.lastBlock。
轮换凭据
TypeScriptimport { rotateMerchantKey, revokeOldMerchantKey } from 'x402-paysdk/merchant';const rotated = await rotateMerchantKey(merchant, { keyType: 'notifyHmacKey' });await secrets.storeNotifyKey(rotated.keyId!, rotated.newKey);// 经过配置的重叠窗口后:await revokeOldMerchantKey(merchant, { keyType: 'notifyHmacKey' });
API key 与 notify key 必须独立轮换。Notify 重叠期应同时接受新旧 key id,随后显式撤销旧 key。
生产门槛
- MerchantClient 只能存在于后端模块。
- Notify 重放保护使用共享原子 nonce store。
- 限制
/txs范围、RPC timeout、响应大小和重试次数。 - 只有同一精确支付上下文的重试才能复用
paymentId。 - 履约写入和支付结算分别重试。
- 收据对、交易哈希和订单一起归档。
- 监控无收据转账、无转账收据、上下文不匹配和退款累计不一致。
- 没有事务型存储时不要启用 order mode。
证据发生冲突时应停止履约,保留 ref snapshot、收据对、交易哈希、订单预期上下文和有界链响应。不能通过接受 notify 数据或发起直接转账来“修复”问题。