> ## Documentation Index
> Fetch the complete documentation index at: https://veniceai-docs-web3-key-siwe-challenge.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# 自主代理 API 密钥创建

> 通过在 Base 上质押 VVV 并用钱包签署 Venice 颁发的 SIWE 挑战消息，让链上 AI agent 自主铸造 Venice API 密钥。

控制 Base 上钱包的 AI agent 可以在无需人类参与的情况下铸造自己的 Venice API 密钥。agent 获取 VVV、质押它、请求一条绑定到自身钱包地址的短期挑战消息，签署该消息并回传，即可获得绑定到质押钱包的全新 API 密钥。

本指南从端到端介绍整个流程，并涵盖密钥铸造后用于实际支付推理的资金选项。

## 前置条件

* agent 控制的 Base 上的 EVM 钱包（私钥保存在环境变量或密钥管理器中）。
* Base 上少量 ETH 用于 gas（质押需要两笔交易：`approve` 然后 `stake`）。
* 任意非零数量的 VVV 用于质押。铸造端点仅要求钱包具备非零 sVVV 余额，因此 1 VVV 足以铸造密钥。请参阅[为推理付费](#paying-for-inference)了解实际调用付费端点需要什么。

<Tip>
  使用专用的 agent 钱包，而不是金库钱包。该钱包的私钥会签署每条 Venice 挑战消息，因此其影响范围应保持最小。
</Tip>

## 步骤

<Steps>
  <Step title="获取 VVV">
    将 VVV 发送到 agent 的钱包，或让 agent 在 DEX（如 [Aerodrome](https://aerodrome.finance/swap?from=eth\&to=0xacfe6019ed1a7dc6f7b508c02d1b04ec88cc21bf\&chain0=8453\&chain1=8453) 或 [Uniswap](https://app.uniswap.org/swap?chain=base\&inputCurrency=NATIVE\&outputCurrency=0xacfe6019ed1a7dc6f7b508c02d1b04ec88cc21bf)）上兑换。

    Base 上的 VVV 代币合约：`0xacfE6019Ed1A7Dc6f7B508C02d1b04ec88cC21bf`
  </Step>

  <Step title="向 Venice 质押 VVV">
    将 VVV 质押到 [Venice 质押智能合约](https://basescan.org/address/0x321b7ff75154472b18edb199033ff4d116f340ff#code) `0x321b7ff75154472B18EDb199033fF4D116F340Ff`。这需要两笔交易：

    1. 在 VVV 代币上调用 `approve(spender, amount)`，其中 `spender` 是质押合约。
    2. 在质押合约上调用 `stake(amount)`。

    <Frame as="div">
      <img src="https://mintcdn.com/veniceai-docs-web3-key-siwe-challenge/gsQAAKgvxVIs7Yrg/images/guides/SC-Stake.png?fit=max&auto=format&n=gsQAAKgvxVIs7Yrg&q=85&s=a6146194096d33bc992caf2257cfdc25" alt="Smart Contract Staking" width="812" height="324" data-path="images/guides/SC-Stake.png" />
    </Frame>

    当第二笔交易确认时，钱包的 VVV 余额减少，其 sVVV 余额相应增加。铸造端点读取 sVVV 余额以确认钱包已质押。
  </Step>

  <Step title="为钱包请求挑战消息">
    调用 `GET /api/v1/api_keys/generate_web3_key?address=<wallet address>` 以获取短期的 [EIP-4361](https://eips.ethereum.org/EIPS/eip-4361)（Sign-In with Ethereum）挑战消息。此端点无需身份验证，但挑战消息会绑定到你传入的地址，只能由该钱包兑换。

    ```bash theme={null}
    curl --request GET \
      --url 'https://api.venice.ai/api/v1/api_keys/generate_web3_key?address=<wallet address>'
    ```

    响应包含 `message`、`nonce` 和 `expiresAt`：

    ```json theme={null}
    {
      "data": {
        "message": "api.venice.ai wants you to sign in with your Ethereum account:\n0x...\n\nAuthorize Venice API key creation. Only sign this on venice.ai — anyone holding this signature can create an API key on your Venice account.\n\nURI: https://api.venice.ai/api/v1/api_keys/generate_web3_key\nVersion: 1\nChain ID: 8453\nNonce: 9f2c1d6b4a8e05337c1b9d2e6f4a7c81\nIssued At: 2026-06-30T11:02:41.167Z\nExpiration Time: 2026-06-30T11:17:41.167Z\nResources:\n- urn:venice:api-key:create",
        "nonce": "9f2c1d6b4a8e05337c1b9d2e6f4a7c81",
        "expiresAt": "2026-06-30T11:17:41.167Z"
      },
      "success": true
    }
    ```

    挑战消息在签发 15 分钟后过期，且**仅可使用一次**——首次用它铸造密钥时即被消耗。每铸造一个密钥都需重新请求。
  </Step>

  <Step title="用质押钱包签署挑战消息">
    用持有质押 VVV 的钱包原样签署 `message` 字符串。这是标准的 `personal_sign`。`ethers.Wallet.signMessage(message)` 和 `viem` 的 `account.signMessage({ message })` 都会产生正确的签名。

    请勿重新格式化、重新换行或重新生成该消息。Venice 会针对其签发的确切字节验证签名，并独立复核其中的 `domain`、`URI`、`Chain ID`、声明文本和地址。
  </Step>

  <Step title="铸造 API 密钥">
    将地址、签名和挑战消息以及您想要的密钥类型 `POST` 到同一端点。

    ```bash theme={null}
    curl --request POST \
      --url https://api.venice.ai/api/v1/api_keys/generate_web3_key \
      --header 'Content-Type: application/json' \
      --data '{
        "address": "<wallet address>",
        "signature": "<signature of the challenge message>",
        "message": "<the unmodified challenge message>",
        "apiKeyType": "INFERENCE",
        "description": "Agent key minted on <date>"
      }'
    ```

    必填字段：`address`、`signature`、`message`、`apiKeyType`（`INFERENCE` 或 `ADMIN`）。

    可选字段：`description`、`expiresAt`、`consumptionLimit`（限制此密钥的总支出，以 `usd`、`vcu` 或 `diem` 计）。

    成功时响应包含铸造的 `apiKey` 字符串。将其存储在 agent 的密钥存储中，并作为正常的 Bearer token（`Authorization: Bearer <key>`）使用。
  </Step>
</Steps>

## 端到端示例

下面的示例使用来自环境变量的真实钱包，而不是随机生成的钱包。随机钱包没有质押的 VVV，铸造将被 `Wallet has no staked VVV on Base` 错误拒绝。

```typescript theme={null}
import { ethers } from "ethers"

const wallet = new ethers.Wallet(process.env.WALLET_PRIVATE_KEY!)
const address = wallet.address

const challengeResponse = await fetch(
  `https://api.venice.ai/api/v1/api_keys/generate_web3_key?address=${address}`,
)
const { data: { message } } = await challengeResponse.json()

const signature = await wallet.signMessage(message)

const mintResponse = await fetch("https://api.venice.ai/api/v1/api_keys/generate_web3_key", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    address,
    signature,
    message,
    apiKeyType: "INFERENCE",
    description: "Agent key",
  }),
})

const result = await mintResponse.json()
if (!mintResponse.ok) {
  throw new Error(`Mint failed: ${result.error}`)
}

console.log("Minted key:", result.data.apiKey)
```

## 错误参考

端点返回具体、可操作的错误消息。在 agent 中映射这些错误，以便它可以决定是重试、请求新挑战消息还是停止。

| 状态    | 错误消息包含                                               | 含义                                          | 应对方式                             |
| ----- | ---------------------------------------------------- | ------------------------------------------- | -------------------------------- |
| `400` | `Invalid wallet address`                             | `address` 字段不是有效的 EVM 地址。                   | 修正地址并重新提交。                       |
| `400` | `The challenge has expired`                          | 挑战消息在您签名并提交之前已过期。                           | 请求新挑战消息，签名并立即提交。                 |
| `400` | `This challenge has already been used`               | 该挑战消息已被兑换。每条最多铸造一个密钥。                       | 每铸造一个密钥都请求一条新的挑战消息。              |
| `400` | `issued for a different wallet address`              | 提交的 `address` 不是该挑战消息签发时绑定的地址。              | 用即将签名的钱包地址作为 `?address=` 请求挑战消息。 |
| `400` | `not a valid Venice API key authorization challenge` | `message` 不是 Venice 挑战消息，或已被修改。             | 发送 `GET` 端点返回的确切 `message` 字符串。  |
| `400` | `The challenge statement was modified`               | 声明行在签发后被更改。                                 | 原样签署该消息。                         |
| `400` | `The challenge domain must be "api.venice.ai"`       | `domain` 行被更改。                              | 原样签署该消息。                         |
| `400` | `Wallet signature does not match`                    | 给定 `message` 的 `signature` 与 `address` 不匹配。 | 用拥有 `address` 的钱包签署确切的消息。        |
| `400` | `Could not verify wallet signature`                  | 验证签名的 RPC 调用失败（瞬态）。                         | 退避后重试。                           |
| `400` | `Wallet has no staked VVV on Base`                   | 钱包的 sVVV 余额为零。                              | 先质押 VVV，然后重试。                    |

## 为什么挑战消息绑定钱包且仅可使用一次

挑战消息是人类可读的 EIP-4361 消息，而非不透明的 token，并提供三项保护。若某个钱包在你自己的 agent 之外被要求签署此类消息，这些保护尤为重要：

* **地址绑定。** 挑战消息载明其签发对应的钱包。一方获取的挑战消息无法由另一个钱包签署并兑换。
* **一次性 nonce。** Venice 在服务端跟踪 nonce，并在首次成功铸造时消耗它。一个签名恰好铸造一个密钥，因此被截获的签名无法重放以获取更多密钥。
* **可读声明。** 该消息明确说明签名将授权创建 Venice API 密钥，因此 MetaMask 等钱包界面会向签名者展示其正在批准的内容，而不是一段二进制数据。

<Warning>
  请将对该消息的签名视同交出在你 Venice 账户上创建 API 密钥的权限。仅签署 `domain` 行为 `api.venice.ai`、且声明中写明创建 Venice API 密钥的挑战消息。`ADMIN` 密钥可以创建和删除其他密钥，并动用你的 DIEM、捆绑额度和 USD 余额。
</Warning>

## 为推理付费

铸造密钥与能够用它调用付费端点是两回事。新铸造的密钥可以正确认证，但在钱包的账户具有可花费余额之前，无法调用付费端点（如 `/chat/completions`）。

铸造的密钥按以下优先顺序从用户账户花费：DIEM，然后是捆绑额度，然后是 USD。

| 资金来源                | 自主？    | 方法                                                                                                       |
| ------------------- | ------ | -------------------------------------------------------------------------------------------------------- |
| **来自 VVV 质押的 DIEM** | 是      | 钱包的每日 DIEM 分配与其在质押池中的份额成比例。账户需要至少 0.1 个质押 DIEM 才能让任何 DIEM 可花费。质押越多，按比例获得更多每日 DIEM，每个 epoch（00:00 UTC）刷新。 |
| **通过 Stripe 的 USD** | 否（浏览器） | 使用相同的钱包登录 venice.ai（Sign-In-With-Ethereum）。仪表板会找到现有的用户记录。在 Settings、API 中添加额度。                           |
| **Coinbase 加密订阅**   | 否（浏览器） | 相同的钱包登录，然后通过仪表板订阅。流程会重定向到 Coinbase Commerce 进行实际付款，因此无法通过脚本驱动。                                           |
| **Coinbase onramp** | 否（浏览器） | 相同的钱包登录，然后在仪表板中使用 onramp 小部件。托管在 Coinbase 的 UI 上。                                                        |

如果 agent 需要完全 crypto 原生、无头的资金路径，最干净的选项是：

1. **质押更多 VVV**，使每日 DIEM 分配覆盖 agent 的支出。铸造的密钥会自动接入。
2. **使用 [x402 钱包流程](/guides/integrations/x402-venice-api) 代替 API 密钥。** 通过 x402，agent 每个请求签署一个 Sign-In-With-X 消息，通过 `POST /api/v1/x402/top-up` 在 Base 或 Solana 上直接用 USDC 充值，并按请求付费。x402 USDC 余额绑定到钱包，而非用户，因此它不会以余额形式出现在铸造的 Bearer 密钥下，但它确实让同一钱包以编程方式为推理付费。

## 相关资源

<CardGroup cols={2}>
  <Card title="Crypto 与 Agents" icon="link" href="/guides/integrations/crypto-rpc-agents">
    将 Venice 同时用作自主 agent 的模型提供商和区块链 RPC 层。
  </Card>

  <Card title="x402 钱包身份验证" icon="wallet" href="/guides/integrations/x402-venice-api">
    在 Base 或 Solana 上用 USDC 按请求付费，无需 API 密钥。
  </Card>

  <Card title="生成 Web3 API 密钥端点" icon="code" href="/api-reference/endpoint/api_keys/generate_web3_key/post">
    铸造端点的端点参考。
  </Card>

  <Card title="标准 API 密钥指南" icon="key" href="/guides/getting-started/generating-api-key">
    适用于希望通过仪表板铸造密钥的用户。
  </Card>
</CardGroup>
