Agent 支付(x402 协议)
AI Agent 可以使用 x402 协议直接从自己的钱包支付 API 调用费用 — 无需 API Key。服务器返回 HTTP 402 并附带支付要求,Agent 签名加密支付授权即可继续。
x402 vs API Key
JarvisClaw 支持两种认证方式 — 底层都使用 x402:
| 方式 | 请求头 | 工作原理 |
|---|---|---|
| API Key | Authorization: Bearer sk-... | 平台代你用 HD 钱包签名 x402(User HD → x402 → JC1) |
| 私钥 (x402 直连) | PAYMENT-SIGNATURE: <base64> | 你的 Agent 直接从自己的钱包签名 x402 |
X-PAYMENT 也可用
X-PAYMENT 是 PAYMENT-SIGNATURE 的等价别名,承载相同的 base64 载荷 —— 如果你的 x402 客户端库 使用生态标准名称,可直接用它。两者同时传入时以 PAYMENT-SIGNATURE 为准。
两种方式都通过 x402 链上结算
使用 API Key 时,服务器自动从你的平台 HD 钱包执行 x402 支付流程 — 你无需处理 402 → 签名 → 重试循环。使用私钥时,你的 Agent 自行处理该循环(SDK 透明完成)。
该选哪个?
- API Key — 最简集成。像任何标准 API 一样使用。你的 HD 钱包余额(Base USDC 或 Solana USDC)会自动扣费,支持多链 fallback。
- 私钥 — 完全自主。你的 Agent 持有自己的密钥并按次支付。最适合管理自有资金的自主 Agent。
工作原理
使用私钥(直连 x402)
- Agent 发送无认证头的请求。
- 服务器返回 HTTP 402 并附带支付要求(金额、Token、链、收款地址)。
- Agent 用钱包私钥签名 x402 支付授权。
- Agent 携带
PAYMENT-SIGNATURE头重发请求。 - 服务器通过 CDP facilitator 合约验证支付并返回响应。
使用 API Key(平台托管 x402)
- 用户携带
Authorization: Bearer sk-...头发送请求。 - 服务器查找用户的 HD 钱包(Base 或 Solana)。
- 服务器自动从 HD 钱包执行 x402 结算(多链 fallback:Base → Solana,当 Base 余额不足时)。
- 成功时返回响应。结算失败时返回 402 并提示充值。
支持的链
| 链 | 网络 ID | 密钥格式 | Token | 状态 |
|---|---|---|---|---|
| Base (EVM) | eip155:8453 | 十六进制私钥 (0x...) | USDC | ✅ 完全支持 |
| Solana | solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp | Base58 密钥对 | USDC (SPL) | ✅ Python SDK |
以上是全部支持的支付链。其他页面出现的链(例如 DEX 交换的目标链、RPC 的多链查询) 指的是被查询或交易的链,不是我们收款的链 —— 付费始终发生在 Base 或 Solana。
方法 1:Python SDK
Python SDK 自动处理 402 握手(获取价格 → 签名 → 重试),你只需提供私钥。
安装
pip install jarvisclaw[agent] # Base (EVM)
pip install jarvisclaw[solana] # Solana
pip install jarvisclaw[all] # 全部EVM(Base 链)
from jarvisclaw import ChatClient, ImageClient, AudioClient, SearchClient
# 所有客户端都接受 private_key — SDK 处理 402 流程
chat = ChatClient(private_key="0x<your-hex-private-key>")
response = chat.complete("你好!")
print(response)
# 检查余额
print(f"余额: ${chat.get_balance():.2f} USDC")
# 其他客户端使用相同方式
image = ImageClient(private_key="0x<your-hex-private-key>")
result = image.generate("火星上的猫")
audio = AudioClient(private_key="0x<your-hex-private-key>")
result = audio.speech("你好世界", voice="sarah")
search = SearchClient(private_key="0x<your-hex-private-key>")
results = search.query("最新 AI 新闻")Solana
from jarvisclaw import ChatClient
# 传入 Solana 密钥对(base58,从 Phantom/Solflare 导出)
chat = ChatClient(private_key="<your-base58-solana-keypair>")
# 相同 API — SDK 从密钥格式检测 Solana 并签名 SPL 转账
response = chat.complete("来自 Solana 的问候!")
print(response)
# 查看 SOL 链 USDC 余额
print(f"余额: ${chat.get_balance():.2f} USDC")异步
from jarvisclaw.aio import ChatClient
async with ChatClient(private_key="0x<your-hex-private-key>") as chat:
text = await chat.complete("说声你好")
print(text)方法 2:Go SDK
Go SDK 支持 Base (EVM) 上的 x402 支付,自动处理 402。
安装
go get github.com/api-jarvisclaw/go-sdk/v2EVM(Base 链)
package main
import (
"context"
"fmt"
"log"
jarvisclaw "github.com/api-jarvisclaw/go-sdk/v2"
)
func main() {
ctx := context.Background()
// x402 钱包认证(无需 API Key)
client, err := jarvisclaw.NewChatClient(
jarvisclaw.WithPrivateKey("0x<your-hex-private-key>"),
)
if err != nil {
log.Fatal(err)
}
text, err := client.Complete(ctx, "来自 Go x402 的问候!")
if err != nil {
log.Fatal(err)
}
fmt.Println(text)
// 查询链上 USDC 余额
balance, _ := client.GetBalance(ctx)
fmt.Printf("钱包余额: $%.4f USDC\n", balance)
}构造函数返回 error
jarvisclaw.NewChatClient 返回 (*ChatClient, error)。忽略第二个返回值无法编译。
API Key(无 x402)
// 传统 API Key 认证 — 不触发 402 流程
client, _ := jarvisclaw.NewChatClient(
jarvisclaw.WithAPIKey("sk-..."),
)Go SDK 暂不支持 Solana
Go SDK 当前仅支持 EVM(Base 链)。如需 Solana x402 支付,请使用 Python SDK。
方法 3:原始 Python(手动 x402 握手)
如果不想使用 SDK,可以用 requests 和 eth_account 手动实现 x402 支付流程。
依赖
pip install requests eth_accountEVM(Base 链)逐步实现
"""手动 x402 支付流程 — 无需 SDK。"""
import base64
import json
import os
import time
import requests
from eth_account import Account
from eth_account.messages import encode_typed_data
BASE_URL = "https://api.jarvisclaw.ai"
PRIVATE_KEY = os.environ["WALLET_PRIVATE_KEY"] # 0x...
account = Account.from_key(PRIVATE_KEY)
# ── 步骤 1:发送请求(无认证)→ 获得 402 ──
resp = requests.post(
f"{BASE_URL}/v1/chat/completions",
headers={"Content-Type": "application/json"},
json={"model": "auto", "messages": [{"role": "user", "content": "你好!"}]},
)
if resp.status_code != 402:
print(resp.json())
raise SystemExit
# ── 步骤 2:解析支付要求 ──
body = resp.json()
payments = body.get("accepts", body.get("payments", []))
payment = next((p for p in payments if p.get("network", "").startswith("eip155:")), None)
if not payment:
raise ValueError("402 响应中没有 EVM 支付选项")
pay_to = payment["payTo"]
amount = int(payment["amount"]) # 单位为微 USDC(6 位小数)
network = payment["network"] # 例如 "eip155:8453"
asset = payment["asset"] # USDC 合约地址
max_timeout = payment.get("maxTimeoutSeconds", 300)
# facilitator 是**顶层**字段,不在 payment["extra"] 里。
# EVM 选项的 extra 装的是 EIP-712 domain:{"name", "version"}。
facilitator = body.get("facilitator", "")
domain_name = payment.get("extra", {}).get("name", "USD Coin")
domain_version = payment.get("extra", {}).get("version", "2")
chain_id = int(network.split(":")[1]) # Base 主网为 8453
# ── 步骤 3:签名 EIP-712 TransferWithAuthorization(EIP-3009)──
valid_after = 0
valid_before = int(time.time()) + max_timeout
nonce = os.urandom(32)
domain = {
"name": domain_name,
"version": domain_version,
"chainId": chain_id,
"verifyingContract": asset,
}
message = {
"from": account.address,
"to": pay_to,
"value": amount,
"validAfter": valid_after,
"validBefore": valid_before,
"nonce": nonce,
}
types = {
"TransferWithAuthorization": [
{"name": "from", "type": "address"},
{"name": "to", "type": "address"},
{"name": "value", "type": "uint256"},
{"name": "validAfter", "type": "uint256"},
{"name": "validBefore", "type": "uint256"},
{"name": "nonce", "type": "bytes32"},
],
}
signed = account.sign_message(encode_typed_data(domain, types, message))
# ── 步骤 4:构造 PAYMENT-SIGNATURE 载荷 ──
payload = {
"x402Version": 2,
"scheme": "exact",
"network": network,
"payload": {
"signature": signed.signature.hex(),
"authorization": {
"from": account.address,
"to": pay_to,
"value": str(amount),
"validAfter": str(valid_after),
"validBefore": str(valid_before),
"nonce": nonce.hex(),
},
},
"extensions": {},
}
signature_header = base64.b64encode(
json.dumps(payload, separators=(",", ":")).encode()
).decode()
# ── 步骤 5:携带 PAYMENT-SIGNATURE 头重试 ──
resp2 = requests.post(
f"{BASE_URL}/v1/chat/completions",
headers={"Content-Type": "application/json", "PAYMENT-SIGNATURE": signature_header},
json={"model": "auto", "messages": [{"role": "user", "content": "你好!"}]},
)
print(resp2.json()["choices"][0]["message"]["content"])402 响应结构
需要付费时服务端返回:
{
"x402Version": 2,
"accepts": [
{
"scheme": "exact",
"network": "eip155:8453",
"asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
"amount": "1000",
"payTo": "0x<seller-address>",
"maxTimeoutSeconds": 300,
"extra": { "name": "USD Coin", "version": "2" }
}
],
"facilitator": "https://api.cdp.coinbase.com/platform/v2/x402",
"resource": {
"url": "https://api.jarvisclaw.ai/v1/chat/completions",
"description": "Chat completion",
"mimeType": "application/json",
"tag": "ai-model"
},
"extensions": {
"bazaar": {
"info": { "input": { "type": "http", "method": "POST", "discoverable": true } },
"schema": { "properties": { "input": {}, "output": {} } }
}
}
}amount 以代币最小单位计(USDC 为 6 位小数,故 1000 = $0.001)。
结构上有两点需要注意:
facilitator是顶层字段,不在accepts[].extra内。extra是 EIP-712 domain:EVM 选项为name、version;Solana 选项为feePayer。
同一份 JSON 也会以 base64 编码放在 PAYMENT-REQUIRED 响应头中;extensions.bazaar 携带 x402scan 用于判定端点可调用的输入/输出 schema。
配置了 Solana 且已知 fee payer 时,服务端会追加第二个支付选项。fee payer 未解析出来之前只列 Base —— 没有它无法构造 SVM 交易。
SDK 会依据钱包密钥格式自动选择:十六进制私钥(0x...)选 eip155:*,Base58 密钥对选 solana:*。
费用与安全
- SDK 内置单次请求安全上限(最高 100 USDC)。服务端要价超过该值时 SDK 会抛错。
client.get_spending()查看本会话累计花费(估算值)。client.get_balance()查看链上剩余 USDC 余额。- 所有支付都是链上授权 —— 你的钱包只签名,不直接转出代币。facilitator 合约在服务端交付响应后 才执行转账。
环境变量
| 变量 | 说明 |
|---|---|
JARVISCLAW_API_KEY | Bearer 认证用的 API Key(与钱包模式互斥) |
JARVISCLAW_WALLET_KEY | 钱包私钥 —— EVM 用十六进制,Solana 用 base58(SDK 自动识别) |
JARVISCLAW_BASE_URL | 覆盖 API 基础地址(默认 https://api.jarvisclaw.ai) |
HD 钱包系统
每个用户注册时自动生成 HD 钱包(Base + Solana)。当使用 API Key 调用时,平台从 HD 钱包余额自动执行 x402 结算。
充值方式
- USDC 转账 — 向你的 HD 钱包地址发送 USDC
- 信用卡/支付宝 — 通过 Airwallex 充值(自动转为链上 USDC)
- 直接持有 — Agent 模式下自行管理钱包余额
多链 Fallback
使用 API Key 且 HD 钱包在 Base 与 Solana 上都有 USDC 时,平台会按顺序自动尝试结算:
- 优先 Base (EVM) —— L2 手续费最低、确认最快。
- 若 Base 结算失败(余额不足、网络错误),自动回退到 Solana。
- 两条链都失败则返回错误 —— 不会调用上游供应商。
TIP
该回退对调用方透明。任一条链(或两条)有余额即可,平台自行选择最优路径,无需配置开关。
结算安全规则
平台强制执行一条规则:若用户钱包在所有链上都结算失败,绝不调用上游供应商。这避免平台为未成功 收费的请求垫付成本。
Solana ATA 预检
尝试 Solana x402 结算前,平台会先做关联代币账户(ATA)预检:
| 检查项 | 验证内容 |
|---|---|
| 发送方 ATA | 付款钱包已初始化 USDC SPL 代币账户 |
| 余额 | 该 ATA 持有足额 USDC |
若 ATA 不存在或余额为零,Solana 路径会被立即跳过(不做失败的交易模拟),转而回退到 Base 或返回错误。
常见问题
从未持有过 USDC 的新 Solana 钱包在链上没有初始化 ATA。你必须先收到至少一笔 USDC 转账 (哪怕 0.000001)来创建 ATA,之后 x402 才能在 Solana 上完成结算。
如何初始化 Solana USDC ATA
- 向你的 Solana 钱包地址发送任意数量的 USDC(SPL)—— 这会自动创建 ATA。
- 或用 Solana 钱包应用(Phantom、Solflare)添加 USDC 代币 —— 部分钱包会主动创建 ATA。
- 平台的
/v1/wallet/balance端点会返回solana下的余额 —— 有返回值即表示 ATA 已就绪。