构建按次计费 API
本指南将指导您如何使用 x402 将 API 端点货币化。服务器添加支付处理程序,客户端按请求付费,并在 HTTP 生命周期内完成结算。
您将构建什么
一个付费 HTTP API,其中服务器以 402 Payment Required 响应,客户端按请求付费,协调器在 HTTP 生命周期内链上结算 USDT0。
演示
步骤 1. 客户端:GET /weather (未支付)
服务器:402 Payment Required
PAYMENT-REQUIRED: { amount: "1000", asset: USDT0, network: eip155:988 }
步骤 2. 客户端签署 ERC-3009 授权
步骤 3. 客户端:GET /weather + PAYMENT-SIGNATURE header
服务器:转发给协调器 → transferWithAuthorization 在链上结算
(~700ms 区块确认)
服务器:200 OK { weather: "sunny", temperature: 70 }
PAYMENT-SETTLE-RESPONSE: { txHash: "0x8f3a...", paid: "0.001 USDT0" }
步骤 4. 在 Stablescan 上验证结算
https://stablescan.xyz/tx/0x8f3a...概述
卖家(服务器):// --- 服务器 ---
app.use(paymentMiddleware({
"GET /weather": {
price: { amount: "1000", asset: USDT0 },
payTo: sellerAddress,
},
"POST /inference": {
price: { amount: "50000", asset: USDT0 },
payTo: sellerAddress,
},
}, resourceServer));
// 配置中未列出的路由不受限制。// --- 客户端 ---
account = new WalletAccountEvm(seedPhrase, { provider: RPC });
client = new x402Client();
fetchWithPayment = wrapFetchWithPayment(fetch, client);
weatherResponse = fetchWithPayment("https://api.example.com/weather");
inferenceResponse = fetchWithPayment("https://api.example.com/inference", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ prompt: "Hello" }),
});
// 对于每个付费请求:
// 1. 初始请求返回 402 和 PAYMENT-REQUIRED 头部
// 2. 客户端使用钱包签署 ERC-3009 授权
// 3. 客户端使用 PAYMENT-SIGNATURE 头部重试
// 4. 协调器在链上结算,服务器返回响应卖家:设置付费端点
卖家添加 x402 中间件来定义哪些路由需要付费。当没有付款的请求到达时,中间件会以 402 Payment Required 和付款条款响应。当存在有效的付款头部时,中间件将其转发给协调器,协调器验证签名并在链上结算付款。卖家只需配置价格和收款地址;协调器处理验证和结算。
npm install express @x402/express @x402/evm @x402/core定价
每个路由都指定以 USDT0 基本单位(6 位小数)计价的支付金额、网络和接收资金的地址。例如,"1000" 等于 $0.001,"50000" 等于 $0.05。
price: {
amount: "1000", // 基本单位 (6 位小数)
asset: USDT0_STABLE, // USDT0 合约地址
extra: { name: "USDT0", version: "1", decimals: 6 }, // EIP-712 域信息
}extra 字段(name、version、decimals)由买方的客户端用于 EIP-712 签名构建,并且必须与链上 USDT0 合约匹配。
路由配置
路由使用 METHOD /path 格式进行映射。每个路由都指定接受的支付方案、网络、价格以及接收资金的地址 (payTo)。description 和 mimeType 字段帮助买家和 AI 代理发现端点提供的信息。配置中未列出的路由不受限制,其行为类似于正常的 Express 路由。
// server.ts
import express from "express";
import { paymentMiddleware, x402ResourceServer } from "@x402/express";
import { ExactEvmScheme } from "@x402/evm/exact/server";
import { HTTPFacilitatorClient } from "@x402/core/server";
const PAY_TO = process.env.PAY_TO_ADDRESS as `0x${string}`;
const FACILITATOR_URL = "https://x402.semanticpay.io/";
const STABLE_NETWORK = "eip155:988"; // Stable 主网 CAIP-2 ID
const USDT0_STABLE = "0x779Ded0c9e1022225f8E0630b35a9b54bE713736";
const facilitatorClient = new HTTPFacilitatorClient({ url: FACILITATOR_URL });
const resourceServer = new x402ResourceServer(facilitatorClient)
.register(STABLE_NETWORK, new ExactEvmScheme());
const app = express();
app.use(
paymentMiddleware(
{
// 示例 1:配置一个付费 GET 路由
"GET /weather": {
accepts: [
{
scheme: "exact",
network: STABLE_NETWORK,
price: {
amount: "1000", // $0.001
asset: USDT0_STABLE,
extra: { name: "USDT0", version: "1", decimals: 6 },
},
payTo: PAY_TO,
},
],
description: "天气数据",
mimeType: "application/json",
},
// 示例 2:配置一个付费 POST 路由
"POST /inference": {
accepts: [
{
scheme: "exact",
network: STABLE_NETWORK,
price: {
amount: "50000", // $0.05
asset: USDT0_STABLE,
extra: { name: "USDT0", version: "1", decimals: 6 },
},
payTo: PAY_TO,
},
],
description: "AI 推理端点",
mimeType: "application/json",
},
},
resourceServer,
),
);
app.get("/weather", (req, res) => {
res.json({ weather: "sunny", temperature: 70 });
});
app.post("/inference", (req, res) => {
const { prompt } = req.body;
res.json({ result: `推理结果为: ${prompt}` });
});
// 未在配置中列出,因此无需支付。
app.get("/health", (req, res) => {
res.json({ status: "ok", payTo: PAY_TO });
});
const PORT = process.env.PORT || 4021;
app.listen(PORT, () => {
console.log(`服务器监听地址 http://localhost:${PORT}`);
console.log(`GET /health - 免费`);
console.log(`GET /weather - 每次请求 $0.001`);
console.log(`POST /inference - 每次请求 $0.05`);
});买家:发出付费请求
买家无需通过手动支付流程即可访问付费端点。买家无需支付 Gas 费。协调器在链上结算,买家只需支付支付要求中指定的精确金额。
npm install @x402/fetch @x402/evm @tetherto/wdk-wallet-evm创建钱包并检查余额
// client.ts
import WalletManagerEvm from "@tetherto/wdk-wallet-evm";
const account = await new WalletManagerEvm(process.env.SEED_PHRASE!, {
provider: "https://rpc.stable.xyz",
}).getAccount(0);
console.log("买家地址:", account.address);
// USDT0 使用 6 位小数。余额 1000000 等于 1.00 USDT0。
const USDT0_STABLE = "0x779Ded0c9e1022225f8E0630b35a9b54bE713736";
const balance = await account.getTokenBalance(USDT0_STABLE);
console.log("USDT0 余额:", Number(balance) / 1e6, "USDT0");连接到 x402 并发出付费请求
WalletAccountEvm 满足 x402 所需的签名者接口,因此可以直接注册为 x402 客户端的签名者。注册后,通过启用 x402 的客户端发送的请求会自动处理 402 支付流程。
import { x402Client, wrapFetchWithPayment } from "@x402/fetch";
import { registerExactEvmScheme } from "@x402/evm/exact/client";
const client = new x402Client();
registerExactEvmScheme(client, { signer: account });
const fetchWithPayment = wrapFetchWithPayment(fetch, client);
const response = await fetchWithPayment("http://localhost:4021/weather");
const data = await response.json();
console.log("响应:", data);在底层,fetchWithPayment 拦截 402 响应,解析支付要求(金额、代币、网络、接收方),使用 WDK 钱包签署 ERC-3009 transferWithAuthorization,并使用 PAYMENT-SIGNATURE 头部重试请求。
测试支付流程
启动服务器并验证付费和免费路由。
1. 确认 402 响应
curl -i http://localhost:4021/weather响应应为 402 Payment Required,并带有包含价格、资产和网络的 PAYMENT-REQUIRED 头部。
2. 运行客户端
npx tsx client.ts客户端处理整个周期:接收 402,签署授权,重试并支付,然后打印响应。
3. 读取收据
成功支付请求后,买方可以从服务器响应中读取 PAYMENT-SETTLE-RESPONSE 头部并解析结算收据。
// (续) client.ts
import { x402HTTPClient } from "@x402/fetch";
const httpClient = new x402HTTPClient(client);
const receipt = httpClient.getPaymentSettleResponse(
(name) => response.headers.get(name),
);
console.log("支付收据:", JSON.stringify(receipt, null, 2));不使用实时协调器进行测试
由于 Semantic 协调器仅限于主网,因此您目前无法将服务器指向测试网协调器。要在不结算实际支付的情况下迭代服务器逻辑、路由处理程序和中间件行为,请使用模拟协调器客户端。
// server.test.ts
import { x402ResourceServer } from "@x402/express";
import { ExactEvmScheme } from "@x402/evm/exact/server";
// 模拟协调器:接受任何签名,返回伪造的结算。
const stubFacilitatorClient = {
verify: async () => ({ isValid: true, payer: "0xMockPayer" }),
settle: async () => ({
success: true,
txHash: "0xMOCK000000000000000000000000000000000000000000000000000000000001",
networkId: "eip155:988",
}),
};
export const testResourceServer = new x402ResourceServer(stubFacilitatorClient as any)
.register("eip155:988", new ExactEvmScheme());针对模拟运行单元测试以验证:
- 402 响应包含正确的
PAYMENT-REQUIRED有效负载。 - 带有有效
PAYMENT-SIGNATURE头的请求到达处理程序。 - 缺少或格式错误的头的请求在处理程序运行前被拒绝。
当您准备好进行真实结算时,请切换回 HTTPFacilitatorClient 并在主网上使用小额资金运行。
高级:生命周期钩子
x402 提供了钩子,可以在流程中的关键点拦截和自定义支付处理。例如,服务器可以在验证之前运行逻辑(例如,检查 API 密钥或订阅者状态)以绕过授权请求的支付,客户端可以在签名之前强制执行消费限制。
有关完整的钩子参考和示例,请参阅 x402 生命周期的钩子。
接下来推荐
- x402 概念:了解协议及其适用范围。
- ERC-3009:回顾 x402 使用的结算标准。
- 使用 MCP 服务器支付:将此 API 封装为 MCP 工具,以便 AI 客户端可以通过提示调用它。

