支付402
机器对机器商务的通用支付层。
HTTP 402(“需要付款”)自1997年以来一直是一个保留的状态码,它是未来软件可以按照重定向的方式为服务付费的占位符。未来就在这里。多种支付协议现在使用402,但它们彼此不兼容:Lightning使用马卡龙和发票,x402在Base上使用EIP-712签名,Solana有自己的流程,Arkade使用比特币VTXO。为一个人建立的客户不能与其他人交谈。
pay402是通用适配器。一个SDK可以说每种402方言,所以你的代码——无论是人工智能代理、MCP服务器、后端服务还是脚本——都可以支付任何402门控端点,无论它使用哪种支付方式。配置您的钱包一次,设置支出限额,以及 client.fetch() 处理一切:挑战解析、轨道选择、支付执行、证明缓存和自动重试。
但pay402不仅仅是客户端支付:
- 架桥车 --没有合适的钱包?pay402通过铁路进行支付。Arkade钱包可以通过Boltz原子交换支付Lightning发票,或者USDC钱包可以通过LendaSat支付。服务器永远不会知道区别。
- 服务器中间件 --只需几行配置,即可在付款后设置自己的Express路线或MCP工具。多轨、多价,插入自己的验证。
- 代理技能 -将pay402注册为MCP工具,这样人工智能代理就可以自主发现、估计和执行付费API调用,并通过支出控制来约束它们。
净效应:任何带有钱包的软件都可以用价格支付任何服务。支付轨道成为一个实现细节,而不是兼容性障碍。
支持的Rails
| 铁路 | 协议 | 货币 | 网络 |
|---|---|---|---|
| L402 | 闪电实验室 | 比特币(sats) | 闪电网络 |
| x402 | Coinbase | USDC | 索拉纳基地 |
Arkade和EVM(USDC)钱包也支持 资金来源 通过桥接层,他们可以通过原子交换(Boltz用于Arkade,LendaSat用于USDC)支付L402发票,但L402也没有面向服务器的支付轨道。
安装
npm install pay402桥接支持的可选对等依赖关系:
npm install @arkade-os/sdk # Arkade wallet
npm install @arkade-os/boltz-swap # Arkade→Lightning bridge
npm install @lendasat/lendaswap-sdk-pure # USDC→Lightning bridge快速开始
最快的运行方式——通过环境变量配置钱包:
# Set at least one wallet
export EVM_PRIVATE_KEY=0x... # for x402 (Base/USDC)
# or
export LND_HOST=https://localhost:8080 # for L402 (Lightning)
export LND_MACAROON=hex-encoded-macaroon
# or
export ARKADE_MNEMONIC="your twelve word mnemonic phrase here"
export ARKADE_SERVER_URL=https://arkade.computer
export ARKADE_NETWORK=mainnet
# Set spend limits
export PAY402_MAX_DAILY=10.00
export PAY402_MAX_PER_REQUEST=1.00import { fromEnv } from "pay402";
const client = fromEnv();
const res = await client.fetch("https://api.example.com/premium-data");
const data = await res.json();就是这样。客户端自动检测配置了哪些钱包,处理402个响应,支付、重试和缓存令牌。看 .env.example 所有可用选项。
在当地试试
git clone https://github.com/RDMoutlaw/pay402.git && cd pay402
npm install
npx tsx examples/mock-server.ts # Terminal 1: starts a 402-gated server
npx tsx examples/client-test.ts # Terminal 2: pays and gets access手动配置
要完全控制,请直接配置客户端:
import { pay402Fetch } from "pay402";
const fetch402 = pay402Fetch({
wallets: [
{
type: "lightning",
lndHost: process.env.LND_HOST!,
lndMacaroon: process.env.LND_MACAROON!,
},
{
type: "evm",
privateKey: process.env.EVM_PRIVATE_KEY! as `0x${string}`,
chain: "base",
},
{
type: "solana",
secretKey: process.env.SOLANA_SECRET_KEY!,
cluster: "mainnet-beta",
},
{
type: "arkade",
mnemonic: process.env.ARKADE_MNEMONIC!,
arkServerUrl: process.env.ARKADE_SERVER_URL!,
network: "mainnet",
},
],
autoFetchBtcPrice: true,
logLevel: "info",
spendControls: {
global: { maxDaily: 10.0, maxPerRequest: 2.0 },
denylist: ["https://*.untrusted.com/**"],
},
});
const res = await fetch402("https://api.example.com/premium-data");
const data = await res.json();API级
import { Pay402Client } from "pay402";
const client = new Pay402Client({
wallets: [{ type: "lightning", lndHost: "...", lndMacaroon: "..." }],
btcPriceUsd: 60000,
maxSinglePaymentUsd: 5,
onPayment: (record) => {
console.log(`Paid $${record.amountUsd} via ${record.rail} to ${record.endpoint}`);
},
});
const res = await client.fetch("https://api.example.com/data");
// Call destroy() when done to stop background tasks (BTC price refresh)
client.destroy();Axios拦截器
import axios from "axios";
import { Pay402Client } from "pay402";
const client = new Pay402Client({ wallets: [...] });
axios.interceptors.request.use((config) => client.intercept(config));跨轨桥梁
当服务器需要您的钱包本机不支持的轨道时,pay402可以桥接付款。例如,Arkade钱包可以通过Boltz潜艇掉期支付Lightning(L402)发票,或者USDC(EVM)钱包可以通过LendaSat原子掉期支付。
桥接是 选择加入 默认情况下禁用:
// Arkade → Lightning
const client = new Pay402Client({
wallets: [
{
type: "arkade",
mnemonic: process.env.ARKADE_MNEMONIC!,
arkServerUrl: "https://arkade.computer",
network: "mainnet",
},
],
bridging: {
enabled: true,
maxBridgeFeeUsd: 0.50, // max bridge fee you're willing to pay
allowedPaths: ["arkade->l402"], // only allow specific bridge paths
},
autoFetchBtcPrice: true,
});
// This works even though the server only accepts L402 (Lightning):
const res = await client.fetch("https://lightning-only-api.com/data");// USDC → Lightning
const client = new Pay402Client({
wallets: [
{
type: "evm",
privateKey: process.env.EVM_PRIVATE_KEY! as `0x${string}`,
chain: "base",
},
],
bridging: {
enabled: true,
maxBridgeFeeUsd: 0.50,
allowedPaths: ["x402-base->l402"],
lendasat: {
chainId: 137, // Polygon (default)
tokenAddress: "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359", // Polygon USDC (default)
},
},
autoFetchBtcPrice: true,
});
// EVM wallet pays a Lightning invoice via LendaSat gasless swap:
const res = await client.fetch("https://lightning-only-api.com/data");服务器看到一个有效的L402预映像——它不知道也不关心付款是如何获得资金的。过桥费包含在支出控制检查中。
当前支持的网桥路径:
| 源 | 目标 | 提供者 | 对等依赖 |
|---|---|---|---|
arkade | l402 | 波尔茨潜艇互换 | @arkade-os/boltz-swap |
x402-base | l402 | LendaSat无气体原子交换 | @lendasat/lendaswap-sdk-pure |
代理技能(MCP客户端工具)
将pay402注册为MCP服务器上的一组工具,以便AI代理可以发现和使用付费API:
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { registerPay402Tools } from "pay402/mcp-tool";
const server = new McpServer({ name: "my-agent", version: "1.0" });
registerPay402Tools(server);这注册了四个工具:
| 工具 | 描述 | 按键输入 |
|---|---|---|
pay402_fetch | 使用402自动支付获取URL | url, method?, headers?, body? |
pay402_estimate | 试运行成本估算 | url, method? |
pay402_spending | 按期间查看支出汇总 | period? (hour, day, all) |
pay402_balance | 检查钱包余额 | -- |
您可以传递预构建的客户端,也可以让它从环境变量自动配置:
// With a pre-built client
const client = new Pay402Client({ wallets: [...] });
registerPay402Tools(server, { client });
// Or auto-configure from env
registerPay402Tools(server);该套餐包括 SKILL.md 代理技能发现文件。
程序性支出与平衡API
客户端还直接公开这些方法:
// Spending summary
const summary = client.getSpendingSummary("hour");
// { totalUsd: 3.50, count: 5, byRail: { l402: { totalUsd: 2.0, count: 3 }, ... } }
// Wallet balances (currently supported for Arkade wallets)
const balances = await client.getBalances();
// [{ type: "arkade", balanceSats: 50000 }, { type: "lightning", error: "balance check not supported" }]服务器中间件——Express
import express from "express";
import { pay402Middleware } from "pay402";
const app = express();
app.use(
pay402Middleware({
pricing: {
"/api/premium/*": { l402: 1000, x402: 500000 }, // 1000 sats or 0.50 USDC
"/api/data": { x402: 100000 }, // 0.10 USDC only
},
acceptedRails: ["l402", "x402"],
verifyL402: (macaroon, preimage) => { /* your verification logic */ },
verifyX402: (payload) => { /* your verification logic */ },
x402PayTo: "0xYourAddress",
x402Asset: "0xUSDCContractAddress",
x402Network: "base",
onPaymentReceived: ({ rail, route, amount }) => {
console.log(`Received payment on ${rail} for ${route}`);
},
})
);
app.get("/api/premium/report", (req, res) => {
res.json({ data: "premium content" });
});MCP支付包装
在不修改工具实现的情况下,将MCP工具置于支付之后。
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { mcpPaymentWrapper } from "pay402";
const server = new McpServer({ name: "my-server", version: "1.0.0" });
// Wrap BEFORE registering tools
mcpPaymentWrapper({
server,
pricing: {
"premium-analysis": { l402: 500, x402: 250000 },
"generate-report": { x402: 1000000 },
},
acceptedRails: ["l402", "x402"],
verifyL402: (macaroon, preimage) => true,
verifyX402: (payload) => true,
x402PayTo: "0xYourAddress",
x402Asset: "0xUSDC",
});
// Register tools as normal — payment is handled by the wrapper
server.registerTool("premium-analysis", { description: "..." }, async (args) => {
return { content: [{ type: "text", text: "analysis result" }] };
});当一个工具在没有付款的情况下被调用时,包装器会返回一个结构化错误:
{
"error": "payment_required",
"version": "pay402/1.0",
"challenges": [
{ "rail": "l402", "amountSats": 500 },
{ "rail": "x402", "network": "base", "amountSmallestUnit": 250000, "payTo": "0x...", "asset": "0x...", "maxTimeoutSeconds": 60 },
]
}调用客户端在重试时使用证明 _payment_proof 参数。
配置参考
钱包类型
| 类型 | 必填字段 | 可选 |
|---|---|---|
lightning | lndHost, lndMacaroon | tlsCert |
evm | privateKey (前缀0x), chain | rpcUrl, facilitatorUrl |
solana | secretKey, cluster | facilitatorUrl |
arkade | mnemonic, arkServerUrl, network | — |
环境变量
| 变量 | 钱包 | 描述 |
|---|---|---|
LND_HOST | Lightning | LND REST API主机 |
LND_MACAROON | Lightning | 十六进制编码的管理员马卡龙 |
LND_TLS_CERT | Lightning | 自签名节点的Base64 TLS证书 |
EVM_PRIVATE_KEY | EVM | 0x前缀的十六进制私钥 |
EVM_CHAIN | EVM | base 或 base-sepolia (默认值: base) |
EVM_FACILITATOR_URL | EVM | x402主持人URL |
SOLANA_SECRET_KEY | Solana | Base58编码的密钥对 |
SOLANA_CLUSTER | 索拉纳 | mainnet-beta 或 devnet (默认值: mainnet-beta) |
SOLANA_FACILITATOR_URL | Solana | x402主持人URL |
ARKADE_MNEMONIC | Arkade | BIP-39助记符短语 |
ARKADE_SERVER_URL | Arkade | Arkade 服务器 URL |
ARKADE_NETWORK 阿卡德 | mainnet 或 testnet (默认值: mainnet) | |
PAY402_MAX_PER_REQUEST | -- | 每次请求的最高美元数 |
PAY402_MAX_HOURLY | -- | 每滚动小时最高美元 |
PAY402_MAX_DAILY | -- | 每个滚动日的最高美元 |
PAY402_BTC_PRICE_USD | -- | BTC的美元静态价格 |
PAY402_AUTO_BTC_PRICE | — | true 从CoinGecko自动获取 |
PAY402_LOG_LEVEL | -- | 日志记录级别 |
支出控制
{
perEndpoint: {
"https://api.example.com/*": { maxPerRequest: 0.50, maxDaily: 5.00 }
},
global: {
maxPerRequest: 2.00, // USD
maxHourly: 10.00, // rolling window
maxDaily: 50.00, // rolling window
},
railPreference: ["x402-base", "l402"], // or "cheapest"
allowlist: ["https://trusted.com/**"],
denylist: ["https://*.evil.com/**"],
dryRun: false,
}有关为自主代理配置支出策略的完整指南(预算层、审批工作流、多代理设置和紧急控制),请参阅 代理支出政策指南.
桥接配置
{
bridging: {
enabled: true, // default: false
maxBridgeFeeUsd: 1.00, // default: $1
allowedPaths: ["arkade->l402", "x402-base->l402"], // restrict which bridge paths are allowed
lendasat: { // optional LendaSat config
chainId: 137, // default: 137 (Polygon)
tokenAddress: "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359", // default: Polygon USDC
},
},
}干运行模式
const client = new Pay402Client({
wallets: [...],
spendControls: { dryRun: true },
});
const res = await client.fetch("https://api.example.com/data");
const estimate = await res.json();
// { rail: "x402-base", estimatedCostUsd: 1.0, wouldExceedLimits: false }错误处理
所有错误都会扩展 Pay402Error:
| 错误 | 何时 |
|---|---|
NoCompatibleRailError | 没有适配器与任何广告轨道匹配,或者没有配置钱包 |
SpendLimitExceededError | 任何支出控制检查都失败 |
PaymentFailedError | 适配器 pay() 已抛出-无自动重试(资金危在旦夕) |
PaymentInFlightError | LND返回IN_FLIGHT--结果未知 |
PaymentVerificationError | 付款后服务器仍返回402 |
InvoiceExpiredError | BOLT11发票在付款尝试前已过期 |
BridgePaymentFailedError | 网桥交换失败(包括 bridgePath 现场) |
import { SpendLimitExceededError, PaymentFailedError, BridgePaymentFailedError } from "pay402";
try {
await client.fetch("https://api.example.com/data");
} catch (err) {
if (err instanceof SpendLimitExceededError) {
console.log(`Limit hit: ${err.limitType}, tried $${err.attemptedAmountUsd}`);
}
if (err instanceof PaymentFailedError) {
console.log(`Payment failed on ${err.rail}: ${err.underlyingError.message}`);
}
if (err instanceof BridgePaymentFailedError) {
console.log(`Bridge failed on ${err.bridgePath}: ${err.underlyingError.message}`);
}
}日志记录
结构化JSON日志记录 皮诺通过配置或环境变量进行设置:
const client = new Pay402Client({ wallets: [...], logLevel: "debug" });或者: PAY402_LOG_LEVEL=debug (无声|致命|错误|警告|信息|调试|跟踪)
在适当的级别记录支付事件、缓存命中、轨道选择和挑战解析。
实时BTC价格
// Auto-fetch and refresh every 5 minutes (CoinGecko)
const client = new Pay402Client({
wallets: [...],
autoFetchBtcPrice: true,
btcPriceUsd: 60000, // fallback until first fetch completes
});
// Or use the provider directly
import { createBtcPriceProvider } from "pay402";
const provider = createBtcPriceProvider({ initialPrice: 60000 });
console.log(provider.getPrice()); // latest price
provider.stop(); // cleanup运作原理
- 客户端向402门控端点发出请求
- 服务器返回
402随着WWW-Authenticate(L402)和/或X-Payment-Required(x402)接头 - SDK解析来自所有标头的挑战
- 检查令牌缓存——如果存在有效的缓存证明,则跳过付款
- 运行支出控制检查——如果超过任何限制,则阻止
- 根据钱包可用性和偏好配置选择最佳轨道
- 如果未启用直接匹配和桥接,则尝试跨轨桥接(例如Arkade->L402)
- 通过匹配的轨道适配器(或网桥提供商)执行付款
- 返回带有付款证明标头的原始请求
- 缓存令牌以备将来请求
- 返回响应——调用者永远看不到402
安全
这个SDK处理私钥和真钱。记住这些:
- 切勿硬编码私钥或助记符。 从环境变量或秘密管理器加载它们。
- x402主持人是值得信赖的第三方。 使用x402时,您签署的EIP-3009授权将提交给主持人(默认:
x402.org).主持人执行链上转移。恶意协助者可能会扣留或预先运行交易。使用facilitatorUrl指向你信任的主持人。 - 过桥交易涉及第三方。 方舟→L402桥采用Boltz进行海底互换;USDC→L402网桥使用LendaSat进行原子交换。过桥费包含在支出控制检查中,但掉期本身就是与相应服务的信任关系。
- 支出控制是你的安全网。 始终配置
maxSinglePaymentUsd和global.maxDaily对于自主代理。默认的硬上限是每笔付款10美元。 - 付款失败后不会自动重试。 如果支付失败,SDK会立即抛出。它不会尝试另一条铁路——钱可能已经离开了你的钱包。
- 轨道之间没有自动回退。 铁路选择发生在付款之前。一旦选择了轨道并开始付款,就没有转换。
要报告安全漏洞,请打开私人问题或直接向维护人员发送电子邮件。
贡献
git clone https://github.com/RDMoutlaw/pay402.git
cd pay402
npm install
npm test # run tests
npm run typecheck # type-check without emittingPR欢迎。请包括新功能的测试。
许可证
麻省理工学院
