跳到正文

完整支付流程

从所有权证明到链上确认,配置商户后端和付款客户端。

本指南构建默认无状态支付路径。你的应用拥有订单记录,网关负责引用和协议协调,链状态与 signed receipt 提供支付证据。

PAYMENT PATH一次授权,跨越五个信任边界
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 的后端密钥系统。
Shell
npm install x402-paysdk

1. 证明 payTo 所有权

TypeScript
import { 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});

立即把 apiKeynotifyHmacKeynotifyHmacKeyId 存入密钥系统。原始凭据只会在签发或轮换时返回。

2. 创建后端 MerchantClient

TypeScript
import { 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。

TypeScript
import { 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. 接入付款钱包

TypeScript
import type { WalletSigner } from 'x402-paysdk/pay';const wallet: WalletSigner = { address: account.address, signTypedData: (typedData) => walletClient.signTypedData(typedData)};

签名前可以先显示并确认精确上下文:

TypeScript
import { 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. 授权并结算

TypeScript
import { 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. 把证据交给后端

TypeScript
await 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. 验证收据与链上终局性

TypeScript
import { 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 作为快速提示

TypeScript
import { 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 没有进入日志。

继续阅读生产运营来设置恢复和对账。