プログラムによる登録:エージェントと CI のためのウォレット署名ログインと API key 作成

AI エージェント、スクリプト、CI ワークフロー向けに、ブラウザーを使わずイーサリアムウォレットの署名(EIP-191)を用いてプログラムから登録し API key を作成します。

ブラウザーのない環境で実行される自律型 AI エージェント、CI パイプライン、自動化スクリプト向けに、BlockVectra はイーサリアムウォレットの署名(EIP-4361 / EIP-191)に基づくプログラムからのログインおよびアカウント作成ワークフローを提供しています。

Key security

秘密鍵、セッショントークン、API key を AI との会話に貼り付けたり、MCP ツールの引数として渡したりしないでください。

登録する前に、まずキー不要の公開エンドポイント https://api.blockvectra.com/v1/robinhood_mainnet/public を試すことができます(ウォレット向け JSON-RPC メソッドのみ利用可能で、Data API にはキーが必要です。メソッドと制限は /v1/chains に従います)。クォータが不足している場合はアカウントを登録してください。

ワークフローの概要

プログラムによる登録とキーのプロビジョニングフローは、4 つのステップで構成されます:

  1. challenge のリクエスト:POST /auth/siwe/challenge にリクエストを送信し、サーバーが生成したサインインメッセージを取得します。
  2. メッセージへの署名:イーサリアム EOA ウォレットを使用して、EIP-191(personal_sign)でメッセージ本文にそのまま署名します。
  3. ログイン / アカウント作成:メッセージ本文と署名を POST /auth/siwe/login に送信します。ウォレットによる初回のサインイン時に、アカウントが自動的に作成されます(account_created: true)。新規アカウントは登録時に 30,000,000 CU を受け取れます。クレジットカードは不要です。
  4. API key の作成:セッショントークンを使用して POST /keys を呼び出し、API key を作成します。

そのまま実行可能な完全なコード例

ここから開始:ローカルのイーサリアム EOA 署名ツールを使用し、キーを作成して、eth_blockNumber で検証します。 Bash の例では、curl、jq、Foundry cast が必要です。ウォレットの認証情報はローカルの署名環境に安全に保管してください。

スターターテンプレートの完全版:blockvectra/agent-quickstart

以下のスクリプトは、ウォレットの認証情報を読み取り、challenge とログインのシーケンスを完了し、API key をプロビジョニングし、環境設定用の export BLOCKVECTRA_API_KEY=... をエクスポートまたは出力して、検証用の eth_blockNumber リクエストを送信します:

新しいキーが有効になるまで数秒かかります。これらの例では自動的に再試行が行われます。

BASE=https://console-api.blockvectra.com/v1
# $ADDR: Ethereum wallet address (0x...)
# $PK: wallet private key, loaded from a secrets manager (never hardcode in scripts)

# 1. Fetch server-generated SIWE message (omit Origin header)
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. Sign the exact message with EIP-191 personal_sign
SIG=$(cast wallet sign --private-key "$PK" "$(cat msg.txt)")

# 3. Submit verbatim message and signature (omit Origin header) to log in (ref is optional)
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. Create an API key (the secret is returned only once)
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. Call JSON-RPC with the key in the x-api-key request header
RPC_DEADLINE=$((SECONDS + 10))
while true; do
  RPC_TIMEOUT=$((RPC_DEADLINE - SECONDS))
  if ((RPC_TIMEOUT <= 0)); then
    printf '%s' "${RPC_BODY:-}"
    break
  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 -e --arg status "$RPC_STATUS" '
      ($status == "401" and .error.data.reason == "invalid_api_key") or
      ($status == "503" and .error.code == -32021)
    ' >/dev/null 2>&1; then
    sleep 2
  else
    printf '%s' "$RPC_BODY"
    break
  fi
done

Base URL とプログラムモード

すべての認証およびキー管理エンドポイントは、公式のベース URL を使用します:

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

Origin ヘッダーの省略

プログラムによるリクエストはプログラムモードで動作します:

  • challenge(POST /auth/siwe/challenge)と login(POST /auth/siwe/login)の両方のリクエストで、Origin ヘッダーを含めてはなりません(curl や標準的な HTTP クライアントはデフォルトでこのヘッダーを省略します。手動で追加しないでください)。
  • Origin ヘッダーが送信され、それが設定済みの Web コンソールドメインでない場合(空文字列や null を含む)、challenge リクエストは HTTP 400 invalid_request を返します。
  • ログイン時のモードが challenge 時のモードと一致しない場合(例えば、Origin なしでプログラム用 challenge をリクエストした後に Origin ヘッダー付きでログインを送信した場合、またはその逆)、login リクエストは HTTP 400 siwe_invalid(reason: domain_mismatch)を返します。

メッセージの完全性とウォレットの要件

  • メッセージの改変禁止とそのままの送信:クライアントは、challenge エンドポイントから返されたメッセージテキストをそのまま署名し送信する必要があります。空白、ドメイン、チェーン ID、その他のフィールドを一切変更しないでください。変更を加えると、HTTP 400 siwe_invalid(reason: signature)が返されます。
  • 対応ウォレット:イーサリアムメインネット(チェーン ID 1)の EOA(Externally Owned Account)。署名は 65 バイトの ECDSA 署名(personal_sign)である必要があります。コントラクトウォレット(EIP-1271)およびスマートアカウントはサポートされていません。
  • challenge の有効期間:各 challenge の nonce は 1 回限り有効で、5 分後に失効します。

リクエストボディと登録時のアトリビューション(任意)

POST /auth/siwe/login のリクエストボディには、必須の認証パラメーターと任意の登録アトリビューションフィールドを指定できます:

  • 必須フィールド:
    • message:challenge エンドポイントから取得した完全な SIWE メッセージ文字列。
    • signature:イーサリアムウォレットで EIP-191 を用いて message に署名して生成された、65 バイトの 16 進数署名(0x プレフィックス付き)。
  • 任意のアトリビューションフィールド(新規アカウント作成時に 1 回のみ保存され、それ以降のログインでは無視されます):
    • ref:^[a-z0-9._-]{1,64}$ に一致する小文字のチャネルトークン(小文字の ASCII 英数字、.、_、-、1〜64 文字)。例えば自律型エージェントは、フレームワークやランタイム識別子(例:my-agent.v1)を設定できます。大文字、空文字列、文字数超過、非対応文字を含む不適合な値は、大文字小文字の変換を行わずに HTTP 400 invalid_request を返し、アカウント作成をブロックします。該当しない場合は省略するか null を渡してください。
    • referrer:流入元の URL またはホスト名文字列。文字列以外の型の場合にのみ HTTP 400 を返します。

signup_method などの未定義フィールドを送信すると、HTTP 400 invalid_request が返されます。

セッショントークンと API key

セッショントークンのライフサイクル

  • 形式:rgs_ に続く 64 文字の小文字 16 進数文字列。
  • 有効期間:絶対的な有効期間は 7 日間。24 時間アイドル状態が続くと自動的に失効します。
  • リフレッシュトークンなし:セッショントークンが失効した場合は、新しい challenge とログインフローを開始してください。
  • ヘッダー:リクエストヘッダー Authorization: Bearer rgs_... でセッショントークンを渡します。

API key の作成

  • セッショントークンを指定して POST /keys を呼び出し、API key(rgw_ に続く 64 文字の 16 進数文字列)を作成します。
  • 1 つのアカウントにつき、失効しておらず有効期限内のキー(active + disabled)は最大 20 個まで保持できます。期限切れのキーはカウントされません。これを超えると、HTTP 409 key_limit_reached(reason: active_keys、limit: 20)が返されます。先に不要なキーを失効させてください。この上限は、そのアカウントのすべての識別子、セッション、チェーンに適用されます。キーの作成とローテーションも 24 時間あたり最大 20 回に制限されており、これを超えると HTTP 429 rate_limited(Retry-After: 3600)が返されます。
  • 任意の上限と有効期限:cu_cap(キーのライフタイム CU 上限、ソフトキャップ)および有効期限(expires_in_secs または expires_at、キーポリシーで許可されている最大日数まで)を指定できます。有効期限が切れるか上限に達すると、サーバーは 403(JSON-RPC -32025、理由 key_expired または key_cap_exhausted)を返します。
  • シークレットである api_key は作成時に 1 度だけ返されます。シークレットマネージャーや環境変数に直ちに安全に保管してください。
  • 1 つの API key は、JSON-RPC および Data API において、サポートされているすべてのチェーンで共通して利用できます。

セッションまたは API key を紛失した場合

BlockVectra では、エージェントのアカウント識別子は登録時に使用したイーサリアムウォレットアドレスに紐付けられます。セッショントークンが失効した場合や、API key が紛失・漏洩した場合でも、そのウォレットのみを使用して完全な制御を回復できます:

  1. 同じウォレットで再認証する:challenge をリクエストし、同じウォレットで署名して、ログインリクエスト(POST /auth/siwe/login)を送信します。サーバーは署名を検証し、account_created: false で既存のアカウントにログインして、新しいセッショントークンを発行します。
  2. 新しい API key を作成する:新しいセッショントークンを使用し、Authorization: Bearer <token> ヘッダーを付けて POST /keys に {"label": "..."} を送信します。エンドポイントは HTTP 201 を返し、作成されたキーの詳細が key に、一度限りのシークレットが api_key に含まれます。このキーを直ちに環境変数またはシークレットマネージャーに保存してください。
  3. アカウントのすべてのキーを一覧表示する:
    • エンドポイント:GET /keys
    • ヘッダー:Authorization: Bearer <token>
    • クエリパラメーター:任意の include_revoked=true(true の場合、失効したキーを含めます。デフォルトは active / disabled のキーのみ)。
    • レスポンス:HTTP 200 と JSON {"items": [...]}。items 配列の各要素には以下が含まれます:
      • key_id:一意のキー識別子(文字列)
      • label:キーのラベル(文字列または null)
      • status:ステータス("active"、"disabled"、または "revoked")
      • created_at:作成日時(ISO 8601 文字列)
      • revoked_at:失効日時(文字列、未失効の場合は null)
  4. 未使用または漏洩したキーを失効させる:
    • エンドポイント:POST /keys/{key_id}/revoke(注意:パスに対象の key_id を指定した POST を使用し、リクエストボディは空にします)
    • ヘッダー:Authorization: Bearer <token>
    • 動作:冪等です。active または disabled ステータスのキーをいずれも失効させることができます。すでに失効している場合は、変更なしで HTTP 200 を返します。失効後、そのキーを使用したリクエストは拒否されます。
    • レスポンス:失効したキーオブジェクトを返す HTTP 200(フィールドは上記のキーオブジェクトと一致し、status: "revoked" および revoked_at にタイムスタンプが含まれます)。

Key and secret security

ウォレットの秘密鍵と API key は環境変数またはシークレットマネージャーに保管してください。コードリポジトリにコミットしたり、ログに出力したり、AI チャットの会話に貼り付けたりしないでください。

セキュリティ上の推奨事項

  • 短期キーを使用し完了時に失効させる:自動化タスクや一時的なタスクでは、expires_in_secs で有効期間の短いキーを作成し、作業完了後に POST /keys/{key_id}/revoke で直ちに失効させてください。

登録レート制限(signup_rate_limited)

アカウント作成には登録レート制限が適用されます。IP ごとのトークンバケットは 100 アカウントの容量を持ち、IPv4 アドレスまたは IPv6 /64 プレフィックスごとに 1 時間あたり 100 アカウントの割合で補充され、SIWE と OAuth の登録で共有されます:

  • 登録制限を超過した場合、POST /auth/siwe/login は HTTP 429 signup_rate_limited を返し、Retry-After ヘッダーで待機秒数を示します。
  • reason フィールドによって制限の適用範囲が区別されます:
    • per_ip:リクエスト元の IP プレフィックスに対する登録枠が使い果たされた場合。
    • global:プラットフォーム全体の登録上限が使い果たされた場合。
  • 登録レート制限は新規アカウントの登録時のみ評価されます。既存アカウントのログインが登録レート制限によってブロックされることはありません。

関連リソース

  • キー不要の MCP サーバーや機械可読なコンテキストファイルについては、AI エージェント連携ガイドを参照してください。
  • 複数言語によるクライアントの例については、クイックスタートを確認してください。
  • すべてのエラーコード、理由、および自動復旧アクションについては、エラーリファレンスを参照してください。

次のステップ

最終更新:

このページの目次