> ## Documentation Index
> Fetch the complete documentation index at: https://docs.blockradar.co/llms.txt
> Use this file to discover all available pages before exploring further.

# 发起智能体支付

> 让 AI 智能体从 Blockradar 钱包使用稳定币为 API 付费，私钥始终不离开 Blockradar

<Note>
  简而言之<br />
  AI 智能体可以通过开放的智能体支付协议，使用稳定币按请求为 API 和数据付费。借助 Blockradar，智能体从私钥始终保留在 Blockradar 内的钱包付款，使用的正是您已有的[类型化数据签名](/zh/essentials/signing#类型化数据签名（仅限-evm）)端点。
</Note>

## 支持的协议

| 协议 | 网络和代币 |
| - | - |
| [x402](https://www.x402.org) | EVM 链，USDC（EIP-3009） |

<Tip>
  您是向智能体出售服务？请参阅[接收智能体支付](/zh/use-cases/accept-agent-payments)。
</Tip>

## 前提条件

<Steps>
  <Step title="API 密钥">
    从 [Blockradar 控制台](https://dashboard.blockradar.co) 获取您的 API 密钥。进入 **Developers** 生成密钥。
  </Step>

  <Step title="EVM 主钱包">
    在控制台中，于 API 收费所在的链（例如 Base）上创建主钱包（参见[创建主钱包](/zh/guides/create-master-wallet)）。通过 Blockradar 进行的智能体支付仅支持 EVM。
  </Step>

  <Step title="启用 USDC">
    在钱包上启用 USDC，以便跟踪余额和存款。参见[资产管理](/zh/use-cases/asset-management)。
  </Step>
</Steps>

## 为智能体设置独立预算

<Warning>
  签名没有单笔付款的支出上限<br />
  任何持有可访问某个钱包的 API 密钥的人，都可以从该钱包或其地址签署任意金额的付款。Blockradar 不会限制智能体签署的金额。为智能体分配一个专用地址，只存放它被允许支出的资金，以限制行为异常的智能体或泄露的密钥可能造成的损失。
</Warning>

关闭自动归集的子地址非常适合作为智能体预算。向其中充值智能体可支出的金额，智能体的付款就永远不会超过该余额。

<CodeGroup>
  ```bash Curl theme={null}
  curl --request POST \
    --url https://api.blockradar.co/v1/wallets/{walletId}/addresses \
    --header 'Content-Type: application/json' \
    --header 'x-api-key: <api-key>' \
    --data '{
      "name": "Research agent budget",
      "disableAutoSweep": true,
      "metadata": {
        "purpose": "agent-payments"
      }
    }'
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch(
    `https://api.blockradar.co/v1/wallets/${walletId}/addresses`,
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'x-api-key': apiKey
      },
      body: JSON.stringify({
        name: 'Research agent budget',
        disableAutoSweep: true,
        metadata: { purpose: 'agent-payments' }
      })
    }
  ).then(r => r.json());

  console.log('Agent address:', response.data.address);
  console.log('Address ID:', response.data.id);
  ```
</CodeGroup>

<Note>
  请在智能体的地址上保持 `disableAutoSweep: true`。如果开启自动归集，您为智能体充值的 USDC 会被归集到主钱包，智能体的付款将因资金不足而失败。
</Note>

也可以从主钱包付款。在下面的示例中使用主钱包端点，并省略 `addressId`。此时主钱包的全部余额都在智能体的可支配范围内，因此仅在主钱包专供该智能体使用时才这样做。

在 [Checkout 计划](/zh/use-cases/checkout#checkout-计划)下，子地址相关操作不可用，请使用专用于该智能体的主钱包。

***

## x402 工作原理

[x402](https://www.x402.org) 是一种开放协议，允许 API 按请求收费：它以 HTTP `402 Payment Required` 响应，调用方随后携带已签名的 USDC 付款重试请求。x402 涉及三方：**买方**（您的智能体）、**卖方**（被付费的 API），以及负责校验付款并将其提交上链的 **facilitator**。

<Steps>
  <Step title="API 请求付款">
    智能体调用付费端点。API 返回 `402 Payment Required`，以及列出其接受条件的 `PAYMENT-REQUIRED` 请求头：网络、代币、金额和 `payTo` 地址。
  </Step>

  <Step title="Blockradar 签署付款">
    智能体将其中一个选项转换为 [EIP-3009](https://eips.ethereum.org/EIPS/eip-3009) `TransferWithAuthorization`，并通过 Blockradar 的类型化数据端点进行签名。此时尚未向链上发送任何内容。
  </Step>

  <Step title="智能体携带签名重试">
    智能体重新发送请求，并在 `PAYMENT-SIGNATURE` 请求头中附上已签名的付款。
  </Step>

  <Step title="facilitator 完成结算">
    卖方的 facilitator 验证签名并将转账提交上链，由其自行支付 Gas。API 返回响应，结算结果位于 `PAYMENT-RESPONSE` 响应头中。
  </Step>
</Steps>

智能体的钱包需要 **USDC，但不需要 Gas**。签名只授权一笔向确定地址转账确定金额的交易，facilitator 无法更改其中任何一项。

***

## 使用 x402 付款

请先按照[为智能体设置独立预算](#为智能体设置独立预算)中的说明为智能体的地址充值。

### 方式 1：使用 x402 客户端 SDK

官方的 [`@x402/fetch`](https://www.npmjs.com/package/@x402/fetch) 客户端会替您处理 402 交互。它只需要一个具有 `address` 和 `signTypedData` 方法的签名器。下面的适配器基于 Blockradar 的类型化数据端点实现了该签名器，因此密钥始终保留在 Blockradar 中。

```bash theme={null}
npm install @x402/fetch @x402/evm
```

```javascript JavaScript theme={null}
import { wrapFetchWithPaymentFromConfig, decodePaymentResponseHeader } from '@x402/fetch';
import { ExactEvmScheme } from '@x402/evm';

// An x402 signer whose key stays in Blockradar. Pass addressId to pay from a child address.
function blockradarSigner({ apiKey, walletId, addressId, address }) {
  const path = addressId
    ? `/wallets/${walletId}/addresses/${addressId}/signing/typed-data`
    : `/wallets/${walletId}/signing/typed-data`;

  return {
    address,
    async signTypedData({ domain, types, message }) {
      // Blockradar derives the domain type from `domain`, so EIP712Domain must not be in `types`
      const { EIP712Domain, ...signTypes } = types;

      const res = await fetch(`https://api.blockradar.co/v1${path}`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json', 'x-api-key': apiKey },
        // x402 passes uint256 values as BigInt, which JSON.stringify cannot serialize
        body: JSON.stringify({ domain, types: signTypes, message }, (_, v) =>
          typeof v === 'bigint' ? v.toString() : v
        ),
      });
      const body = await res.json();
      if (!res.ok) {
        throw new Error(`Blockradar signing failed: ${JSON.stringify(body.message)}`);
      }
      if (body.data.senderAddress.toLowerCase() !== address.toLowerCase()) {
        throw new Error(`Signed by ${body.data.senderAddress}, expected ${address}`);
      }
      return body.data.signedTransaction.signature;
    },
  };
}

const signer = blockradarSigner({
  apiKey: process.env.BLOCKRADAR_API_KEY,
  walletId: process.env.BLOCKRADAR_WALLET_ID,
  addressId: process.env.BLOCKRADAR_ADDRESS_ID, // omit to pay from the master wallet
  address: process.env.AGENT_ADDRESS,           // the address that holds the USDC
});

const fetchWithPayment = wrapFetchWithPaymentFromConfig(fetch, {
  schemes: [{ network: 'eip155:8453', client: new ExactEvmScheme(signer) }], // Base mainnet
});

const response = await fetchWithPayment('https://api.example.com/premium-data');
console.log(await response.json());

const settlement = response.headers.get('PAYMENT-RESPONSE');
if (settlement) {
  console.log(decodePaymentResponseHeader(settlement)); // { success, transaction, network, payer }
}
```

为智能体付款的每个网络注册一个 scheme（测试时 Base Sepolia 使用 `eip155:84532`），并确保每个网络背后都有该链上的钱包。

### 方式 2：自行构建付款

不使用 SDK 或使用其他语言时，一次付款需要三次 HTTP 调用：首次请求、调用 Blockradar 签名，以及付费后的重试。以下步骤在 Base 上支付 0.01 USDC。

#### 第 1 步：读取付款要求

调用 API。`402` 响应带有一个 base64 编码的 `PAYMENT-REQUIRED` 请求头。解码后如下所示：

```json theme={null}
{
  "x402Version": 2,
  "error": "PAYMENT-SIGNATURE header is required",
  "resource": {
    "url": "https://api.example.com/premium-data",
    "description": "Access to premium market data",
    "mimeType": "application/json"
  },
  "accepts": [
    {
      "scheme": "exact",
      "network": "eip155:8453",
      "amount": "10000",
      "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
      "payTo": "0x209693Bc6afc0C5328bA36FaF03C514EF312287C",
      "maxTimeoutSeconds": 60,
      "extra": {
        "name": "USD Coin",
        "version": "2"
      }
    }
  ]
}
```

在 `accepts` 中选择一个您的钱包可以支付的条目：

* `scheme` 为 `exact`。
* `network` 为钱包所在的链。`eip155:8453` 是 Base 主网。
* `extra.assetTransferMethod` 不存在或为 `eip3009`。`permit2` 方式需要先进行链上代币授权，这会消耗 Gas，因此本指南不涉及。

`amount` 以代币的最小单位表示。USDC 有 6 位小数，因此 `10000` 即 0.01 USDC。

#### 第 2 步：签署授权

根据付款要求构建 `TransferWithAuthorization`，并从智能体的地址签名：

| 字段 | 值 |
| - | - |
| `domain.name`、`domain.version` | `extra.name` 和 `extra.version` |
| `domain.chainId` | `network` 中 `eip155:` 之后的数字，作为 JSON 数字 |
| `domain.verifyingContract` | `asset`，即 USDC 合约 |
| `message.from` | 智能体的地址 |
| `message.to` | `payTo` |
| `message.value` | `amount` |
| `message.validAfter` | 略早于当前时间的 Unix 时间，例如当前时间减去 600 秒 |
| `message.validBefore` | 当前时间加上 `maxTimeoutSeconds` |
| `message.nonce` | 32 个随机字节的十六进制表示。每次付款都要生成新的 nonce |

<CodeGroup>
  ```bash Curl theme={null}
  curl --request POST \
    --url https://api.blockradar.co/v1/wallets/{walletId}/addresses/{addressId}/signing/typed-data \
    --header 'Content-Type: application/json' \
    --header 'x-api-key: <api-key>' \
    --data '{
      "domain": {
        "name": "USD Coin",
        "version": "2",
        "chainId": 8453,
        "verifyingContract": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
      },
      "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" }
        ]
      },
      "message": {
        "from": "0x947514e4B803e312C312da0F1B41fEDdbe15ae7a",
        "to": "0x209693Bc6afc0C5328bA36FaF03C514EF312287C",
        "value": "10000",
        "validAfter": "1791106604",
        "validBefore": "1791107264",
        "nonce": "0x312a453ed3d129ba71de863aa623245c0e5e120bad410d995cea6739aa8ee98b"
      }
    }'
  ```

  ```javascript JavaScript theme={null}
  import { randomBytes } from 'node:crypto';

  const now = Math.floor(Date.now() / 1000);
  const authorization = {
    from: agentAddress,
    to: accepted.payTo,
    value: accepted.amount,
    validAfter: String(now - 600),
    validBefore: String(now + accepted.maxTimeoutSeconds),
    nonce: '0x' + randomBytes(32).toString('hex'),
  };

  const res = await fetch(
    `https://api.blockradar.co/v1/wallets/${walletId}/addresses/${addressId}/signing/typed-data`,
    {
      method: 'POST',
      headers: { 'Content-Type': 'application/json', 'x-api-key': apiKey },
      body: JSON.stringify({
        domain: {
          name: accepted.extra.name,
          version: accepted.extra.version,
          chainId: Number(accepted.network.split(':')[1]),
          verifyingContract: accepted.asset,
        },
        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' },
          ],
        },
        message: authorization,
      }),
    }
  );
  const signed = await res.json();
  if (!res.ok) throw new Error(`Signing failed: ${JSON.stringify(signed.message)}`);

  const signature = signed.data.signedTransaction.signature;
  ```
</CodeGroup>

如需改为从主钱包签名，请使用 `POST /v1/wallets/{walletId}/signing/typed-data`，并将 `from` 设为主钱包的地址。响应为标准的[类型化数据响应](/zh/essentials/signing#类型化数据响应)；签名位于 `data.signedTransaction.signature` 中。

#### 第 3 步：携带付款重试

将签名和授权封装到付款载荷中，进行 base64 编码，并在同一请求的 `PAYMENT-SIGNATURE` 请求头中发送：

```javascript JavaScript theme={null}
const paymentPayload = {
  x402Version: 2,
  resource: paymentRequired.resource,
  accepted,                              // the entry you chose from `accepts`
  payload: { signature, authorization },
};

const paid = await fetch('https://api.example.com/premium-data', {
  headers: {
    'PAYMENT-SIGNATURE': Buffer.from(JSON.stringify(paymentPayload)).toString('base64'),
  },
});
```

#### 第 4 步：检查结算结果

成功的响应包含一个 base64 编码的 `PAYMENT-RESPONSE` 响应头：

```json theme={null}
{
  "success": true,
  "transaction": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
  "network": "eip155:8453",
  "payer": "0x947514e4B803e312C312da0F1B41fEDdbe15ae7a"
}
```

`transaction` 是 USDC 转账的链上哈希。如果付款失败，API 会再次返回 `402`，`PAYMENT-RESPONSE` 中会带有 `errorReason`，例如 `insufficient_funds`。

<Accordion title="调用 x402 v1 API">
  使用 x402 版本 1 的服务器与上述流程有四点不同：

  * 付款要求位于 `402` 响应的**正文**中，而不是请求头中。
  * 网络使用名称（`base`、`base-sepolia`），而不是 `eip155:<chainId>`。Base 的链 ID 为 `8453`；Base Sepolia 为 `84532`。
  * 金额字段为 `maxAmountRequired`，而不是 `amount`。
  * 付款放在 `X-PAYMENT` 请求头中，格式为 base64 编码的 JSON，包含 `x402Version: 1`、`scheme`、`network` 以及相同的 `payload` 对象；结算结果通过 `X-PAYMENT-RESPONSE` 返回。

  使用 Blockradar 的签名步骤完全相同。
</Accordion>

### 集成中容易出错的签名规则

| 规则 | 违反时的结果 |
| - | - |
| `domain.chainId` 是与钱包所在链匹配的 JSON 数字 | `400 Chain ID mismatch`。字符串形式的 `"8453"` 同样会失败。 |
| `types` 中只包含 `TransferWithAuthorization` | 在 `types` 中包含 `EIP712Domain` 会导致 `ambiguous primary types or unused types` 错误。Blockradar 会根据 `domain` 构建域类型。 |
| `message.from` 是签名的地址 | 签名恢复出的地址与之不同，facilitator 会拒绝该付款。 |
| 每次付款使用新的 `nonce` | USDC 会拒绝重复使用的 nonce，付款将无法结算。 |
| 付款地址持有足够的 USDC | facilitator 会以余额不足为由拒绝付款。不需要 Gas。 |

每个签名都会被记录为一笔 `SIGNED` 交易，并触发 `signed.success` [Webhook](/zh/essentials/signing#webhook-事件)，为您的智能体授权的每笔付款提供审计记录。签名并不等于付款：只有当卖方的 facilitator 完成结算时，USDC 才会转移。当卖方不在 Blockradar 上时，结算会显示为从智能体地址发出的转账。对账时，请将 `signed.success` Webhook 与 `PAYMENT-RESPONSE` 标头中的链上交易进行匹配。

***

## x402 的限制

* **仅支持 EVM。** 付款使用 EIP-712 类型化数据签名，而 Blockradar 仅在 EVM 链上支持该功能。不支持 Solana 及其他非 EVM 的 x402 网络。
* **仅支持 EIP-3009 `exact` 付款。** 支持具有 `transferWithAuthorization` 的代币，例如 USDC。不涉及 `permit2` 转账方式和其他 scheme。
* **不支持 Circle Gateway 纳米支付。** Circle 的批量亚美分付款选项尚未在 Blockradar 钱包上测试。

***

## 最佳实践

* **在智能体中强制执行限额。** Blockradar 会签署来自有效 API 密钥的任何格式正确的请求。请在智能体代码中设置单笔和每日限额，并通过智能体地址的余额限制总风险敞口。
* **每个智能体一个地址。** 独立的预算可以清楚显示每个智能体花了多少钱，并让您通过清空其地址来停用某个智能体。
* **签名前检查价格。** 将 `amount` 与您的智能体为该资源最多应支付的金额进行比较，拒绝任何更高的价格。
* **检查收款方。** 如果您的智能体只为已知 API 付款，请维护一份 `payTo` 地址白名单。
* **使用 `metadata` 和 Webhook。** 使用 `metadata` 标记智能体地址，并将 `signed.success` Webhook 与每个 `PAYMENT-RESPONSE` 中的链上交易进行对账。
* **锁定 API 访问。** 通过 [IP 白名单](/zh/use-cases/ip-whitelist)仅接受来自您自己服务器的 API 请求，使泄露的密钥无法在其他地方使用。
* **先在 Base Sepolia 上测试。** 在动用真实资金之前，使用测试网钱包（`eip155:84532`）以及来自[水龙头](/zh/use-cases/supported-assets)的测试网 USDC。

***

## API 参考

| 端点 | 说明 |
| - | - |
| [Sign Typed Data (Master Wallet)](/zh/api-reference/signing/master-wallet-typed-data) | 从主钱包签署付款授权 |
| [Sign Typed Data (Child Address)](/zh/api-reference/signing/child-address-typed-data) | 从子地址签署付款授权 |
| [Generate Address](/zh/api-reference/addresses/generate-address) | 为智能体预算创建专用地址 |
| [Update Address](/zh/api-reference/addresses/update-address) | 为地址开启或关闭自动归集 |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.