完整支付流程
从所有权证明到链上确认,配置商户后端和付款客户端。
本指南构建默认无状态支付路径。你的应用拥有订单记录,网关负责引用和协议协调,链状态与 signed receipt 提供支付证据。
01支付引用
→
商户创建 PaymentRef
02支付报价
→
网关返回已签名 402
03钱包授权
→
钱包签署 EIP-3009
04链上结算
→
Facilitator 广播交易
05终局验证
链状态与收据共同验证
资金从付款授权直接进入 payTo;网关不会持有钱包私钥或用户余额。
准备条件
- 已部署的 x402 网关,例如
https://pay.example.com。 - 商户控制的 EVM
payTo钱包。 - 对应网络上支持 EIP-3009 的 USDC。
- 能签署 EIP-712 typed data 的付款钱包适配器。
- 保存 API key 和 notify HMAC key 的后端密钥系统。
Shellnpm install x402-paysdk
1. 证明 payTo 所有权
TypeScriptimport { createMerchantChallenge, merchantChallengeTypedData, registerMerchant} from 'x402-paysdk/merchant';const gateway = 'https://pay.example.com';const payTo = '0x1111111111111111111111111111111111111111';const webhookUrl = 'https://merchant.example/x402/notify';const challenge = await createMerchantChallenge(gateway, { payTo, network: 'base', action: 'merchant.register', webhookUrl});const signature = await merchantWallet.signTypedData( merchantChallengeTypedData(challenge.message));const credentials = await registerMerchant(gateway, { challengeId: challenge.challengeId, payTo, network: 'base', label: '示例商店', webhookUrl, signature});
立即把 apiKey、notifyHmacKey 和 notifyHmacKeyId 存入密钥系统。原始凭据只会在签发或轮换时返回。
2. 创建后端 MerchantClient
TypeScriptimport { MerchantClient } from 'x402-paysdk/merchant';const merchant = new MerchantClient({ gateway, apiKey: process.env.X402_API_KEY!, notifyHmacKey: process.env.X402_NOTIFY_KEY!, notifyHmacKeyId: process.env.X402_NOTIFY_KEY_ID!, payTo, network: 'base'});
这个客户端只能在后端创建,不能序列化到前端状态,也不能记录它的配置。
3. 创建并保存 PaymentRef
金额使用 USDC 原子单位,六位精度下 24000000 表示 24 USDC。
TypeScriptimport { createPaymentRef } from 'x402-paysdk/merchant';const ref = await createPaymentRef(merchant, { payTo, network: 'base', asset: 'USDC', amount: '24000000', invoiceId: 'order_7K9M2', label: '订单 7K9M2', expiresInSecs: 900, notifyUrl: webhookUrl});await orders.savePaymentReference({ orderId: 'order_7K9M2', refId: ref.refId, refUrl: ref.refUrl, expectedAmount: ref.snapshot.amount, expectedPayTo: ref.snapshot.payTo, expiresAt: ref.snapshot.expiresAt});
只把 refUrl 和显示信息交给付款端。它可以通过链接、二维码、deep link 或 API payload 传递。
4. 接入付款钱包
TypeScriptimport type { WalletSigner } from 'x402-paysdk/pay';const wallet: WalletSigner = { address: account.address, signTypedData: (typedData) => walletClient.signTypedData(typedData)};
签名前可以先显示并确认精确上下文:
TypeScriptimport { getPaymentRequired } from 'x402-paysdk/pay';const required = await getPaymentRequired(ref.refUrl);const offer = required.accepts[0];renderConfirmation({ payTo: offer.payTo, amount: offer.amount, network: offer.network, asset: offer.asset});
5. 授权并结算
TypeScriptimport { pay } from 'x402-paysdk/pay';const settlement = await pay({ refUrl: ref.refUrl, paymentId: crypto.randomUUID(), wallet});
pay() 会解析 receive URL、获取 402、验证 signed offer 和网关 DID、生成 EIP-3009 typed data、请求钱包签名并提交 PAYMENT-SIGNATURE。
6. 把证据交给后端
TypeScriptawait fetch('/api/orders/order_7K9M2/payment', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ txHash: settlement.txHash, signedReceipt: settlement.signedPaymentReceipt, receipt: settlement.receipt })});
7. 验证收据与链上终局性
TypeScriptimport { verifyReceipt } from 'x402-paysdk/merchant';const verification = await verifyReceipt(merchant, { signedReceipt, receipt, expectedPayTo: order.expectedPayTo, expectedAmount: order.expectedAmount, minConfirmations: 3});if (!verification.valid || !verification.confirmed) { throw new Error(verification.reason ?? '支付尚未达到终局状态');}await orders.markPaidOnce(order.id, { txHash: verification.txHash!, payer: verification.payer!, receipt});
markPaidOnce 必须是商户数据库内的原子操作。默认网关不会替商户持有履约状态。
8. 把 notify 作为快速提示
TypeScriptimport { verifySettlementNotify } from 'x402-paysdk/merchant';const result = await verifySettlementNotify( request.headers, rawBody, { [process.env.X402_NOTIFY_KEY_ID!]: process.env.X402_NOTIFY_KEY! }, sharedNonceStore);if (!result.ok) return new Response('invalid notify', { status: 401 });await paymentQueue.enqueue(result.notify);return new Response(null, { status: 204 });
多实例生产环境必须使用共享原子 nonce store。Notify 只能提前唤醒验证流程,不能代替链上终局性。
完成标准
- 付款方在签名前看到准确的
payTo、金额、网络和资产。 - Signed offer 通过固定 signer 或同源 DID 发现建立信任。
- 后端把收据与订单保存的预期上下文逐项匹配。
- 链上转账达到配置的确认数。
- 履约使用一次原子状态转换。
- 凭据、付款签名和原始 notify body 没有进入日志。
继续阅读生产运营来设置恢复和对账。