# 程序化开户与建 Key：面向 Agent 与 CI 的钱包签名指南

> 原文地址: https://docs.blockvectra.com/zh/guides/programmatic-signup/

面向在无浏览器环境中运行的自主 AI Agent、CI 自动化流水线与脚本，BlockVectra 提供基于以太坊钱包签名（EIP-4361 / EIP-191）的程序化登录与自动开户流程。

> **密钥安全**
>
> 私钥、会话令牌和 API key 不要贴进与 AI 的对话、不要作为 MCP 工具参数。


## 流程概览

程序化开户与创建 API key 包含四个步骤：

1. **获取 challenge**：向 `POST /auth/siwe/challenge` 发送请求，获取服务端生成的签名消息。
2. **对消息签名**：使用以太坊 EOA 钱包，通过 EIP-191（`personal_sign`）对消息原文进行签名。
3. **登录 / 自动开户**：将消息原文与签名提交至 `POST /auth/siwe/login`。钱包首次登录会自动开户（`account_created: true`）。新账户注册即得 3,000 万 CU，无需信用卡。
4. **创建 API key**：携带返回的会话令牌调用 `POST /keys`，创建 API key。

## Base 地址与程序化模式

所有控制面认证与 key 管理接口均使用正式 Base 地址：

```
https://console-api.blockvectra.com/v1
```

### 不带 Origin 请求头

程序化请求工作在**程序化模式**：

* challenge（`POST /auth/siwe/challenge`）和 login（`POST /auth/siwe/login`）两个请求都**不带 `Origin` 请求头**（`curl` 与常用 HTTP 客户端默认不附带该头；请勿手动添加）。
* 在程序化模式下，服务端签发的消息中 domain 固定为 `console-api.blockvectra.com`，URI 固定为 `https://console-api.blockvectra.com`。
* 若请求中带有 `Origin` 请求头，但取值不是配置的网页控制台域名（包括空值或 `null`），challenge 请求直接返回 HTTP 400 `invalid_request`。
* 若登录时提交的模式与 challenge 时的模式不一致（例如以程序化模式获取 challenge 后，提交 login 时附带了 `Origin` 请求头，反之亦然），login 请求返回 HTTP 400 `siwe_invalid`，原因码为 `domain_mismatch`。

### 消息原文与钱包要求

* **原样签名、原样提交**：客户端必须对 challenge 返回的 `message` 原文进行签名并原样提交，严禁修改任何空格、换行、域名或链 ID。服务端在验签前会将提交的消息与服务端存储的消息逐字节比对；篡改任何内容均会返回 HTTP 400 `siwe_invalid`，原因码为 `signature`。
* **支持的钱包**：以太坊主网（Chain ID 1）的 EOA（Externally Owned Account）钱包。签名必须为 65 字节 ECDSA 签名（`personal_sign`）。不支持合约钱包（EIP-1271）与智能账户（smart accounts）。
* **challenge 有效期**：每个 challenge 的 nonce 仅限使用一次，5 分钟内有效。

## 会话令牌与 API key

### 会话令牌生命周期

* **格式**：`rgs_` + 64 位小写十六进制字符串。
* **有效期**：绝对有效 7 天；连续空闲 24 小时后失效。
* **无 refresh token**：会话失效后重新执行 challenge 与 login 流程获取新令牌。
* **传递方式**：在请求头中传入 `Authorization: Bearer rgs_...`。

### 创建 API key

* 携带会话令牌调用 `POST /keys`，创建 API key（`rgw_` + 64 位十六进制字符串）。
* 响应中的 `api_key` **只出现这一次**，请立即妥善保存至密钥管理系统或环境变量中。
* 一个 API key 可用于所有支持链的 JSON-RPC 与 Data API。

## 开户限流（`signup_rate_limited`）

为保障服务稳定性，新开户操作受开户限额约束：

* 超出限额时，`POST /auth/siwe/login` 返回 HTTP 429 `signup_rate_limited`，并带有 `Retry-After` 响应头（秒数）。
* 错误体中的 `reason` 字段区分限额维度：
  * `per_ip`：同一 IP 前缀的开户预算已耗尽。
  * `global`：全平台开户上限已耗尽。
* 开户限流仅在新建账户时生效，已有账户登录不受开户限流影响。

## 完整 Bash 示例

以下脚本从环境变量 `$ADDR` 读取钱包地址，从密钥管理读取钱包私钥 `$PK`，完成 challenge、签名、登录、建 key 全流程，将生成的 key 写入环境变量 `BLOCKVECTRA_API_KEY`，并通过请求头调用一次 `eth_blockNumber`：

```bash
BASE=https://console-api.blockvectra.com/v1
# $ADDR: 以太坊钱包地址 (0x...)
# $PK: 钱包私钥，从密钥管理系统读入（严禁写进脚本或命令历史）

# 1. 获取服务端签发的 SIWE 消息（不带 Origin 请求头）
curl -s "$BASE/auth/siwe/challenge" -H 'Content-Type: application/json' \
  -d "{\"address\":\"$ADDR\",\"purpose\":\"login\"}" > challenge.json
jq -r .message challenge.json > msg.txt

# 2. 用钱包对消息原文做 EIP-191 personal_sign 签名
SIG=$(cast wallet sign --private-key "$PK" "$(cat msg.txt)")

# 3. 原样提交消息原文与签名（同样不带 Origin 请求头）完成登录
jq -n --rawfile m msg.txt --arg s "$SIG" '{message: ($m | rtrimstr("\n")), signature: $s}' |
  curl -s "$BASE/auth/siwe/login" -H 'Content-Type: application/json' -d @- > session.json
TOKEN=$(jq -r .session.token session.json)

# 4. 创建 API key（secret 仅返回一次）
KEY_RESP=$(curl -s "$BASE/keys" \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"label":"agent-key"}')
export BLOCKVECTRA_API_KEY=$(echo "$KEY_RESP" | jq -r .api_key)

# 5. 用请求头携带 key 发送 JSON-RPC 请求
curl -s "https://api.blockvectra.com/v1/robinhood_mainnet" \
  -H "x-api-key: $BLOCKVECTRA_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"eth_blockNumber","params":[]}'
```

## 相关资源

* 阅读 [AI Agent 接入指南](https://docs.blockvectra.com/zh/guides/ai-agents/)，了解免 key 的 MCP 服务与机器可读上下文文件。
* 查看[快速上手](https://docs.blockvectra.com/zh/quickstart/)获取更多语言的客户端接入代码。
* 查看[错误参考页](https://docs.blockvectra.com/zh/errors/)了解所有错误码、原因码与自动化处置建议。

## 下一步

* [浏览数据集目录](https://blockvectra.com/zh/data/)，查看 BlockVectra 索引的全部数据集。
* [查看免费额度与定价](https://blockvectra.com/zh/pricing/#free)，确认账户可用的方案。
* [登录控制台](https://console.blockvectra.com/zh/login/?next=%2Fzh%2Fkeys%2F)创建 API key。
