AI Agent 如何不开浏览器拿到区块链 API key:SIWE 钱包登录
开发者与 AI Agent 不开浏览器,用 3 次 BlockVectra HTTP 请求加本地钱包签名,完成 4 个步骤取得区块链 API key:SIWE challenge、本地签名、login、POST /keys。注册即送 30,000,000 CU,无需先付款。
AI Agent 不开浏览器拿到 BlockVectra API key 需完成 4 个步骤:3 次 BlockVectra HTTP 请求加本地钱包签名,依次为获取 SIWE challenge、用以太坊钱包在本地签名、login、POST /keys。钱包首次登录即自动开户并赠送 30,000,000 CU,无需先付款。先发出第一条调用(核对于 ):
BASE=https://console-api.blockvectra.com/v1
curl -s "$BASE/auth/siwe/challenge" -H 'Content-Type: application/json' \
-d "{\"address\":\"$ADDR\",\"purpose\":\"login\"}"同一流程适用于在无浏览器环境中运行的自主 AI Agent、CI 流水线与脚本,基于以太坊钱包签名(EIP-4361 / SIWE 消息,用 personal_sign(EIP-191)签名)。
密钥安全
私钥、会话令牌和 API key 不要贴进与 AI 的对话、不要作为 MCP 工具参数。
在开户前,可先使用免 key 公开端点 https://api.blockvectra.com/v1/robinhood_mainnet/public 进行测试(Robinhood Chain 上该端点仅允许钱包类 JSON-RPC 方法;各链允许的方法不同,以 list_chains 或 GET /v1/chains 里的 public.methods 为准;Data API 需要 key),额度不够再开户。
流程概览
程序化开户与创建 API key 包含四个步骤:
- 获取 challenge:向
POST /auth/siwe/challenge发送请求,获取服务端生成的签名消息。 - 对消息签名:使用以太坊 EOA 钱包,通过
personal_sign(EIP-191)对 EIP-4361 消息原文进行签名。 - 登录 / 自动开户:将消息原文与签名提交至
POST /auth/siwe/login。钱包首次登录会自动开户(account_created: true)。新账户注册即得 30,000,000 CU,无需信用卡。 - 创建 API key:携带返回的会话令牌调用
POST /keys,创建 API key。
最短 curl 序列
3 次 BlockVectra HTTP 请求加本地钱包签名(4 个步骤),随后用独立的带 key HTTP 请求调用 eth_blockNumber 验证 key。ADDR 为钱包地址(0x...),PK 为其私钥,从密钥管理系统读入;需要 curl、jq 与 Foundry cast。新 key 生效需要几秒,遇到 401 invalid_api_key 请稍等后重试(下方完整示例会自动重试)。
BASE=https://console-api.blockvectra.com/v1
# 1. challenge:服务端返回待签的消息原文
MSG=$(curl -s "$BASE/auth/siwe/challenge" -H 'Content-Type: application/json' \
-d "{\"address\":\"$ADDR\",\"purpose\":\"login\"}" | jq -r .message)
# 2. 用 EIP-191 personal_sign 签名
SIG=$(cast wallet sign --private-key "$PK" "$MSG")
# 3. login:钱包首次登录自动开户
TOKEN=$(jq -n --arg m "$MSG" --arg s "$SIG" '{message: $m, signature: $s}' |
curl -s "$BASE/auth/siwe/login" -H 'Content-Type: application/json' -d @- | jq -r .session.token)
# 4. 创建 API key(secret 仅返回一次)
KEY=$(curl -s "$BASE/keys" -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{"label":"agent-key"}' | jq -r .api_key)
# 5. 用 x-api-key 请求头携带 key 调用 JSON-RPC
RESP=$(curl -s "https://api.blockvectra.com/v1/robinhood_mainnet" -H "x-api-key: $KEY" -H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"eth_blockNumber","params":[]}' \
-w '\n%{http_code}') &&
printf '%s' "${RESP%$'\n'*}" | jq -es --arg status "${RESP##*$'\n'}" '
if length == 1 and (.[0] | type) == "object" and ($status | test("^2[0-9][0-9]\\z")) and
(.[0] | .jsonrpc == "2.0" and (.id | type) == "number" and .id == 1 and has("error") == false and
(.result | type) == "string" and (.result | test("^0x(0|[1-9a-fA-F][0-9a-fA-F]*)\\z")))
then .[0] else empty end'完整复制即跑示例
从这里开始:使用本地以太坊 EOA 签名工具,创建 key,并通过 eth_blockNumber 验证。
对于 Bash 示例,需要安装 curl、jq 与 Foundry cast。请在本地签名环境中妥善保管钱包凭据。
完整模板仓库:blockvectra/agent-quickstart
以下代码从环境变量读取钱包凭据,完成 challenge、签名、登录、建 key 全流程,将生成的 key 导出或打印提示 export BLOCKVECTRA_API_KEY=...,并通过请求头调用一次 eth_blockNumber:
新 key 生效需要几秒,示例会自动重试。
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 请求头)完成登录(ref 字段可选)
jq -n --rawfile m msg.txt --arg s "$SIG" '{message: ($m | rtrimstr("\n")), signature: $s, ref: "docs-signup"}' |
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 请求
RPC_DEADLINE=$((SECONDS + 10))
while true; do
RPC_TIMEOUT=$((RPC_DEADLINE - SECONDS))
if ((RPC_TIMEOUT <= 0)); then
printf '%s' "${RPC_BODY:-}"
echo "RPC verification failed: retry budget exhausted" >&2
exit 1
fi
RPC_RESP=$(curl -s --max-time "$RPC_TIMEOUT" -w '\n%{http_code}' "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":[]}') || { rc=$?; echo "request failed (curl exit $rc)" >&2; exit $rc; }
RPC_STATUS=${RPC_RESP##*$'\n'}
RPC_BODY=${RPC_RESP%$'\n'*}
if ((SECONDS + 2 < RPC_DEADLINE)) &&
printf '%s' "$RPC_BODY" | jq -es --arg status "$RPC_STATUS" '
length == 1 and (.[0] | type) == "object" and (
($status == "401" and .[0].error.data.reason == "invalid_api_key") or
($status == "503" and .[0].error.code == -32021))
' >/dev/null 2>&1; then
sleep 2
continue
fi
printf '%s' "$RPC_BODY"
printf '%s' "$RPC_BODY" | jq -es --arg status "$RPC_STATUS" '
length == 1 and (.[0] | type) == "object" and ($status | test("^2[0-9][0-9]\\z")) and
(.[0] | .jsonrpc == "2.0" and (.id | type) == "number" and .id == 1 and has("error") == false and
(.result | type) == "string" and (.result | test("^0x(0|[1-9a-fA-F][0-9a-fA-F]*)\\z")))
' >/dev/null 2>&1 || { echo "RPC verification failed (HTTP $RPC_STATUS)" >&2; exit 1; }
break
doneBase 地址与程序化模式
所有认证与 key 管理接口均使用正式 Base 地址:
https://console-api.blockvectra.com/v1不带 Origin 请求头
程序化请求工作在程序化模式:
- challenge(
POST /auth/siwe/challenge)和 login(POST /auth/siwe/login)两个请求都不带Origin请求头(curl与常用 HTTP 客户端默认不附带该头;请勿手动添加)。 - 若请求中带有
Origin请求头,但取值不是配置的网页控制台域名(包括空值或null),challenge 请求直接返回 HTTP 400invalid_request。 - 若登录时提交的模式与 challenge 时的模式不一致(例如以程序化模式获取 challenge 后,提交 login 时附带了
Origin请求头,反之亦然),login 请求返回 HTTP 400siwe_invalid,原因码为domain_mismatch。
消息原文与钱包要求
- 原样签名、原样提交:客户端必须对 challenge 返回的
message原文进行签名并原样提交,严禁修改任何空格、换行、域名或链 ID。篡改任何内容均会返回 HTTP 400siwe_invalid,原因码为signature。 - 支持的钱包:以太坊主网(Chain ID 1)的 EOA(Externally Owned Account)钱包。签名必须为 65 字节 ECDSA 签名(
personal_sign)。不支持合约钱包(EIP-1271)与智能账户(smart accounts)。 - challenge 有效期:每个 challenge 的 nonce 仅限使用一次,5 分钟内有效。
请求体参数与注册归因(可选)
POST /auth/siwe/login 的请求体包含必选的认证字段与可选的来源归因字段:
- 必选字段:
message:从 challenge 端点获取的完整 SIWE 消息字符串。signature:以太坊钱包用personal_sign(EIP-191)对 EIP-4361message签名得到的 65 字节十六进制签名(0x开头)。
- 可选归因字段(仅在首次登录新开户时随账户保存一次,后续登录不再改写):
ref:小写渠道标记,格式为^[a-z0-9._-]{1,64}$(仅允许小写字母、数字、.、_、-,1–64 个字符)。例如自主 Agent 可在此传入自身框架或运行环境名(如my-agent.v1)。不合规的值(包含大写字母、空串、超长或非法字符)一律返回 HTTP 400invalid_request(不做大小写折叠,亦不开户);不传或为null表示没有渠道标记。referrer:来源 URL 或主机名字符串。省略或传入null均按未提供处理;空字符串或无法提取有效主机名的字符串会被丢弃。仅非null且非字符串的值返回 HTTP 400invalid_request。
请求体中若附带 signup_method 等未定义字段会返回 HTTP 400 invalid_request。
会话令牌与 API key
会话令牌生命周期
- 格式:
rgs_+ 64 位小写十六进制字符串。 - 有效期:绝对有效 7 天;连续空闲 24 小时后失效。
- 无 refresh token:会话失效后重新执行 challenge 与 login 流程获取新令牌。
- 传递方式:在请求头中传入
Authorization: Bearer rgs_...。
创建 API key
- 携带会话令牌调用
POST /keys,创建 API key(rgw_+ 64 位十六进制字符串)。 - 默认策略下,每账户最多持有 20 个未吊销且未过期的 key(
active+disabled)。只有未吊销且expires_at为null或严格晚于当前时刻的 key 才计入,已过期的 key 不计入;超出实际配置上限时返回 HTTP 409key_limit_reached,附error.reason: active_keys,error.limit为实际配置上限,请先吊销一个 key。该上限由账户下所有身份、会话与链共享。默认滚动 24 小时创建上限也是 20 次;超出时返回 HTTP 429rate_limited,附error.reason: daily_creations与Retry-After: 3600。 - 在创建配额检查中,先检查有效 key 数量上限,再检查滚动 24 小时创建上限;若同时达到两者,创建请求返回有效 key 上限的 HTTP 409,而非每日创建上限的 HTTP 429。轮换要求目标 key 已启用、未吊销且未过期;轮换不增加有效 key 数量,但仍消耗每日创建配额。吊销或过期不会从滚动 24 小时统计中扣除该 key 的创建次数。
- 可选限额与有效期:支持传入
cu_cap(该 key 终身可用的 CU 上限,为软上限)以及有效期(expires_in_secs或expires_at二选一,最长为 key 策略允许的天数);到期或用满上限后,服务端返回 403(JSON-RPC-32025,reason 为key_expired或key_cap_exhausted)。 - 响应中的
api_key只出现这一次,请立即妥善保存至密钥管理系统或环境变量中。 - 一个 API key 可用于所有支持链的 JSON-RPC 与 Data API。
会话或 key 丢了怎么办
在 BlockVectra 中,Agent 的账户身份与开户所用的以太坊钱包地址绑定。当会话令牌过期,或 API key 丢失、泄露时,只需持有该钱包的私钥即可找回账户控制权并换新 key:
- 凭同一个钱包重新签名登录:使用同一钱包地址重新执行获取 challenge、钱包签名并提交登录流程(
POST /auth/siwe/login)。服务端验签通过后直接登录已有账户,返回新会话令牌,且account_created为false。 - 创建新 API key:拿到新会话令牌后,携带
Authorization: Bearer <token>请求头调用POST /keys,在请求体中传入{"label": "..."}。响应为 HTTP 201,返回包含新 key 信息的key对象与只显示一次的api_key字符串(密钥)。将其妥善保存在环境变量或密钥管理系统中。 - 列出本账户的 key:
- 接口:
GET /keys - 请求头:
Authorization: Bearer <token> - Query 参数:可选
include_revoked=true(为true时包含已吊销的 key;默认仅返回未吊销 key)。 - 响应:HTTP 200,返回 JSON 对象
{"items": [...]}。其中items数组的每个元素包含字段:key_id:key 唯一标识(字符串)label:key 标签名(字符串或null)status:状态("active"、"disabled"或"revoked")created_at:创建时间戳revoked_at:吊销时间戳(未吊销时为null)
- 接口:
- 吊销不再使用或泄露的旧 key:
- 接口:
POST /keys/{key_id}/revoke(注意使用POST方法,路径参数为待吊销的key_id,无请求体) - 请求头:
Authorization: Bearer <token> - 行为:操作幂等,
active与disabled状态的 key 均可吊销。已吊销时原样返回 HTTP 200。吊销后,用这个 key 的请求会被拒绝。 - 响应:HTTP 200,返回已吊销 key 的对象(字段同上述单个 key,其中
status为"revoked",revoked_at为吊销时间戳)。
- 接口:
私钥与 key 安全
钱包私钥与 API key 必须妥善保存在环境变量或密钥管理系统中,切勿写入代码仓库、运行日志或与 AI 的对话上下文中。
安全建议
- 短期 key 用完即吊销:对于自动化或短期任务,建议在创建 key 时设置短期有效期(
expires_in_secs),任务执行完毕后及时通过POST /keys/{key_id}/revoke吊销。
开户限流(signup_rate_limited)
新开户操作受开户限额约束。每个 IPv4 地址或 IPv6 /64 前缀的令牌桶容量为 100 个账户,每小时补充 100 个账户的开户配额,由 SIWE 与 OAuth 开户共享:
- 超出限额时,
POST /auth/siwe/login返回 HTTP 429signup_rate_limited,并带有Retry-After响应头(秒数)。 - 错误体中的
reason字段区分限额维度:per_ip:同一 IP 前缀的开户预算已耗尽。global:全平台开户上限已耗尽。
- 开户限流仅在新建账户时生效,已有账户登录不受开户限流影响。
常见问题
拿 key 之前要先付款或充值吗?
不要。钱包首次登录即自动开户并赠送 30,000,000 CU,用登录返回的会话令牌创建 key 即可。首次充值之前,账户每秒最多 25 次调用,详见免费套餐能做什么。
需要浏览器、密码或 gas 吗?
不需要浏览器。HTTP 请求使用普通 HTTPS JSON,不带 Origin 请求头;消息签名在自行具备的钱包环境中本地完成。没有密码,钱包签名就是凭据。签名在链下完成,不花 gas、不发交易。钱包必须是以太坊 EOA,不支持合约钱包(EIP-1271)。
API key 丢了怎么办?
secret 只显示一次,无法再次取回。用同一个钱包重新登录拿到新的会话令牌,创建新 key,再吊销旧 key;详见会话或 key 丢了怎么办。
相关资源
- 阅读 AI Agent 接入指南,了解免 key 的 MCP 服务与机器可读上下文文件。
- 查看快速上手获取更多语言的客户端接入代码。
- 查看错误参考页了解所有错误码、原因码与自动化处置建议。
下一步
- 携带
x-api-key: $BLOCKVECTRA_API_KEY发送首个 JSON-RPC 或 Data API 请求。 - 调用
GET /v1/account查询账户余额与速率上限。 - 参考 Agent 程序化充值指南 为账户充值并保持余额充足。
最后更新: