Skip to content

Agent 支付(x402 协议) ​

AI Agent 可以使用 x402 协议直接从自己的钱包支付 API 调用费用 — 无需 API Key。服务器返回 HTTP 402 并附带支付要求,Agent 签名加密支付授权即可继续。

x402 vs API Key ​

JarvisClaw 支持两种认证方式 — 底层都使用 x402:

方式请求头工作原理
API KeyAuthorization: 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。按模型实际消耗的 token 在调用后计费,包含 prompt 缓存折扣。
  • 私钥 — 完全自主。你的 Agent 持有自己的密钥并按次支付。最适合管理自有资金的自主 Agent。你签名的金额就是实际扣费金额 —— 首次付款前请先读计费规则。

计费规则 ​

首次签名付款前请读这一节。以下规则适用于直连 x402(PAYMENT-SIGNATURE);API Key 路径行为不同,见本节末尾。

报价金额即最终金额 ​

402 挑战里的 amount 就是链上实际结算的金额。它是请求运行之前算出的估值,而且事后不做对账。

网关报价的那一刻无法知道模型会回多长,所以按你的 max_tokens 报价。如果回复比上限短 —— 而绝大多数回复只用到上限的一小部分 —— 差额不退。

max_tokens 请按实际需要设置

在这条路径上,宽松的上限不是免费的。max_tokens: 4096 而实际只回 40 个 token,报价会接近上限并按那个数结算。这是「付得比调用价值多」的最大单一来源。

没有退款、没有返还额度、没有对账环节。非 2xx 响应不结算 —— 失败的调用不扣钱 —— 但成功的调用会按你签名的数字结算。

这条路径不给 prompt 缓存折扣 ​

命中缓存的 prompt token 在直连 x402 路径上按完整输入价计费。

上游会不会从缓存里读你的 prompt,取决于此前已经发生的流量,报价时不可知。如果报了折扣而实际没命中,就会少收且无法追回,所以报价一律按未命中计算。

关于 /api/pricing 里的 cache_ratio

定价接口会给出每个模型的 cache_ratio,它适用于 API Key 路径 —— 那条路径在交付后计费,能读到真实的缓存 token 数。它不会降低直连 x402 的报价。

响应里仍然会如实报告发生了什么 —— prompt_tokens_details.cached_tokens,Anthropic 格式的调用还有 cache_read_input_tokens —— 所以你能看到缓存在生效,只是它没改变本次调用的价格。

最低扣费 ​

每次成功结算至少 $0.001。这是一次链上结算的成本,不是服务费:比这更小的扣费收到的钱不够付交易本身。

它是下限,不是附加费。价值 $0.004 的调用就收 $0.004,不是 $0.005;价值 $0.00002 的调用收 $0.001。

token 不加价 ​

按 token 计费的模型调用以上游原价结算,不加任何加价。媒体生成和少数计量服务有加价,见计费与限额。

如果你需要精确的单次成本 ​

用 API Key。那条路径在交付后按上游真实 token 数结算,收的就是调用实际花的钱,并且会应用缓存折扣。代价是需要账户和一个有余额的 HD 钱包,而不是一个裸密钥对。

以上规则也以机器可读形式发布在 /.well-known/x402 的 billing 字段里。

工作原理 ​

使用私钥(直连 x402) ​

  1. Agent 发送无认证头的请求。
  2. 服务器返回 HTTP 402 并附带支付要求(金额、Token、链、收款地址)。
  3. Agent 用钱包私钥签名 x402 支付授权。
  4. Agent 携带 PAYMENT-SIGNATURE 头重发请求。
  5. 服务器通过 CDP facilitator 合约验证支付并返回响应。

使用 API Key(平台托管 x402) ​

  1. 用户携带 Authorization: Bearer sk-... 头发送请求。
  2. 服务器查找用户的 HD 钱包(Base 或 Solana)。
  3. 服务器自动从 HD 钱包执行 x402 结算(多链 fallback:Base → Solana,当 Base 余额不足时)。
  4. 成功时返回响应。结算失败时返回 402 并提示充值。

支持的链 ​

链网络 ID密钥格式Token状态
Base (EVM)eip155:8453十六进制私钥 (0x...)USDC✅ 完全支持
Solanasolana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpBase58 密钥对USDC (SPL)✅ Python SDK

以上是全部支持的支付链。其他页面出现的链(例如 DEX 交换的目标链、RPC 的多链查询) 指的是被查询或交易的链,不是我们收款的链 —— 付费始终发生在 Base 或 Solana。

方法 1:Python SDK ​

Python SDK 自动处理 402 握手(获取价格 → 签名 → 重试),你只需提供私钥。

安装

shell
pip install jarvisclaw[agent]     # Base (EVM)
pip install jarvisclaw[solana]    # Solana
pip install jarvisclaw[all]       # 全部

EVM(Base 链) ​

python
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 ​

python
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")

异步 ​

python
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。

安装

shell
go get github.com/api-jarvisclaw/go-sdk/v2

EVM(Base 链) ​

go
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) ​

go
// 传统 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 支付流程。

依赖

shell
pip install requests eth_account

EVM(Base 链)逐步实现 ​

python
"""手动 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 响应结构 ​

需要付费时服务端返回:

json
{
  "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_KEYBearer 认证用的 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 结算。

充值方式 ​

  1. USDC 转账 — 向你的 HD 钱包地址发送 USDC
  2. 信用卡/支付宝 — 通过 Airwallex 充值(自动转为链上 USDC)
  3. 直接持有 — Agent 模式下自行管理钱包余额

多链 Fallback ​

使用 API Key 且 HD 钱包在 Base 与 Solana 上都有 USDC 时,平台会按顺序自动尝试结算:

  1. 优先 Base (EVM) —— L2 手续费最低、确认最快。
  2. 若 Base 结算失败(余额不足、网络错误),自动回退到 Solana。
  3. 两条链都失败则返回错误 —— 不会调用上游供应商。

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 ​

  1. 向你的 Solana 钱包地址发送任意数量的 USDC(SPL)—— 这会自动创建 ATA。
  2. 或用 Solana 钱包应用(Phantom、Solflare)添加 USDC 代币 —— 部分钱包会主动创建 ATA。
  3. 平台的 /v1/wallet/balance 端点会返回 solana 下的余额 —— 有返回值即表示 ATA 已就绪。