Agent ID
ERC-8004 に準拠し、第三者が独立して検証できるオンチェーン ID を AI Agent に提供します。
要点: 先に Agent ウォレットを作成してから、ID 登録 API を1回呼び出します。数秒後に、誰でも検証できるオンチェーン ID が Agent に付与されます。ウォレットのオンチェーン紐付けは、登録完了後に別途リクエストする必要があります。
本章は、自分のシステムを BOT Chain Agent ID サービスと連携させる開発者向けです。認証情報の取得、ID の登録、ウォレット紐付けのリクエスト、準備完了の確認、説明情報の更新、利用者を信頼せずに第三者が検証する方法を説明します。
本章のパスはすべて、次のいずれかのベース URL を基準とします。
| 環境 | URL |
|---|---|
| BOT メインネット | https://identity-api.botchain.ai |
| Bohr テストネット | https://identity-api.bohr.life |
1. 概要
| 質問 | 回答 |
|---|---|
| 何を取得できますか? | オンチェーンの agentId と公開された JSON 説明ファイル |
| 認証方法は? | X-API-Key リクエストヘッダー |
| 登録は同期処理ですか? | いいえ。作成はすぐに 202 を返し、オンチェーン処理はバックグラウンドで進みます |
| 完了の確認方法は? | ID の状態をポーリングするか、状態変更の webhook を受信します |
| 所要時間は? | 通常は数秒で、ブロック生成時間によります |
| ガス代は誰が負担しますか? | 当サービスです。連携システムは秘密鍵を保有せず、アカウントへの入金も不要です |
| 第三者が検証できるものは? | owner、Agent ウォレット、説明ファイルの URL。すべてチェーンから直接取得できます |
| 対応チェーンは? | BOT メインネット(chain ID 677)と Bohr テストネット(chain ID 968) |
次の点を覚えておいてください。
API で Agent を説明し、チェーンには所有者と使用するウォレットが記録されます。後者は、他の人があなたに問い合わせずに自分で確認できます。
2. 認証情報の取得
連携する各事業者をプロジェクトとして扱い、プロジェクト ID と1つ以上の API キーを割り当てます。キーは当サービスが発行し、現時点ではセルフサービスでの発行はできません。希望のプロジェクト名をお知らせいただくと、以下を返します。
project_id launchpad
key_id k_01J8XV…
api_key ak_live_k_01J8XV….<secret>
project_id は記録用として利用開始時に通知されます。業務リクエストに project_id を含める必要はなく、送信しないでください。サーバーは API キーからテナントを特定するため、本文を変更して別のプロジェクトにリソースを作成することはできません。
API キーはドットで区切られた2つの部分からなります。
ak_<environment>_k_<key_id>.<secret>
<environment> は発行環境のラベル(live や test など)であり、project_id ではありません。所属プロジェクトはサーバー側の api_keys テーブルに保存され、key_id に紐付けられます。
ドットを含む文字列全体を X-API-Key に設定してください。secret は作成時に一度だけ返され、その後は取得できません。 すぐにシークレット管理システムへ保存してください。紛失した場合は再発行と旧キーの失効が必要で、復元する方法はありません。
キーは環境別です。テストネット用キーはメインネットでは使えません。
3. ID の登録
ID は特定の Agent ウォレットに対して登録するため、wallet_id と wallet_address はどちらも必須で、既存ウォレットの値である必要があります。先にウォレットを作成してください。Agent ウォレット を参照してください。
1つの wallet_id を関連付けられる ID は、サービス全体で1つだけです。別の ID に再利用すると 409 が返ります。
POST /v1/agents/identities
Content-Type: application/json
X-API-Key: ak_…
Idempotency-Key: <冪等キー>
{
"external_agent_id": "自分の-agent-id",
"wallet_id": "wal_de43139cef869dc9c4…",
"chain_id": 677,
"owner_address": "0x5f5802fA78d5eE2A3B4fD67F49CD502430C3E88C",
"wallet_address": "0xd9DC4F46d9da603A2A077A7190BAa85f4e2f05fe",
"metadata": {
"name": "サンプル Agent",
"description": "この Agent の役割"
},
"callback_url": "https://your-service.example/webhooks/identity"
}
| フィールド | 必須 | 意味 |
|---|---|---|
external_agent_id | はい | 自分のシステム内の Agent 識別子。プロジェクトとチェーンの範囲で一意 |
wallet_id | はい | この ID が属する Agent ウォレット(サービス全体で一意) |
chain_id | はい | メインネットは 677、テストネットは 968。他の値は不可 |
owner_address | はい | この ID を制御するアドレス。有効な EVM アドレスが必要 |
wallet_address | はい | Agent が取引に使うウォレットのアドレス。有効な EVM アドレスが必要 |
metadata | はい | 自由形式の説明。name は必須で空にできません |
callback_url | いいえ | 状態変更を送る絶対 http/https URL。省略時はポーリングを利用 |
idempotency_key | はい | 本文または Idempotency-Key ヘッダーで指定 |
リクエスト本文にプロジェクト ID や鍵素材は含めません。プロジェクトは API キーから特定されるため、別の値を渡して他人のプロジェクトに ID を作成することはできません。
external_agent_id は (プロジェクト, チェーン) 内で一意です。同じ (プロジェクト, チェーン, external_agent_id) で再度作成すると、リクエスト内容に違いがあっても既存の ID と "replayed": true が返り、2件目は作成されません。別の ID がすでに使用している wallet_id など、永続的な競合の場合のみ 409 が返ります。
202 Accepted を返します。ID レコードは作成済みですが、オンチェーン処理はまだ行われていません。
{
"identity": {
"identity_id": "idn_c39e39dd-1030-4c33-b888-5beeb876247d",
"project_id": "launchpad",
"external_agent_id": "自分の-agent-id",
"wallet_id": "wal_de43139cef869dc9c4…",
"chain_id": 677,
"owner_address": "0x5f5802fa78d5ee2a3b4fd67f49cd502430c3e88c",
"wallet_address": "0xd9dc4f46d9da603a2a077a7190baa85f4e2f05fe",
"registry_address": "0xb43edfb9c7609cf645e932b2ff20f26f0d4488de",
"status": "PENDING",
"wallet_binding_status": "PENDING",
"created_at": "2026-09-08T06:12:44Z",
"updated_at": "2026-09-08T06:12:44Z"
},
"replayed": false
}
以降の各 API で使うため、identity_id を保存してください。 作成時にキューへ入るのは、owner へのガス代補充と、それに続く register() / 正式なメタデータの公開のみです。ウォレット紐付けは自動ではキューに入りません。
書き込み API は ID オブジェクトを identity で包みますが、読み取り API はオブジェクトを直接返します。作成後は response.identity.status、GET 後は response.status を参照します。両方を同じ方法で読むことが、連携時に最もよくある誤りです。
冪等性
論理的な作成処理ごとに一意の Idempotency-Key を使ってください。同じキーで再送すると、202 ではなく 200 と "replayed": true が返り、タイムアウト後の再試行でも別の ID は作られません。キーは自分の Agent ID から導出し、HTTP リクエストのたびにランダム生成しないでください。それでは冪等性が失われます。
4. 登録完了を待つ
登録はバックグラウンドで複数の段階を通ります。個別に処理する必要はなく、status が REGISTERED になることを確認してください。
| 状態 | 意味 |
|---|---|
PENDING | 受け付け済み、キューで待機 |
GAS_FUNDING | owner アカウントへガス代を補充中 |
REGISTERING | register() 送信済み、オンチェーンへの取り込み待ち |
METADATA_PENDING | 正式な登録ファイルを公開または更新中。初回登録後と、その後のメタデータ更新時にこの状態になります |
REGISTERED | 登録完了。 erc8004_agent_id と metadata_uri が設定済み |
WALLET_BINDING | ウォレット紐付けトランザクションを送信済み。オンチェーンでの確定を待ち、確定後に REGISTERED に戻ります |
wallet_binding_status は独立して進みます。オンチェーンの紐付けが完了すると PENDING から CONFIRMED になります。
ID が REGISTERED でも、紐付けが未リクエスト、またはリクエスト済みでもトランザクションが未送信の場合、wallet_binding_status は PENDING のままです。紐付けトランザクションの確定待ちの間、status は一時的に WALLET_BINDING になります。
4.1 ポーリング
GET /v1/agents/identities/{identity_id}
X-API-Key: ak_…
読み取り API はラッパーなしで ID オブジェクトを直接返します。
{
"identity_id": "idn_c39e39dd-1030-4c33-b888-5beeb876247d",
"project_id": "launchpad",
"wallet_id": "wal_de43139cef869dc9c4…",
"status": "REGISTERED",
"wallet_binding_status": "CONFIRMED",
"erc8004_agent_id": "45",
"registry_address": "0xb43edfb9c7609cf645e932b2ff20f26f0d4488de",
"metadata_uri": "https://…/v2-….json",
"owner_address": "0x5f5802fa78d5ee2a3b4fd67f49cd502430c3e88c",
"wallet_address": "0xd9dc4f46d9da603a2a077a7190baa85f4e2f05fe",
"updated_at": "2026-09-08T06:12:51Z"
}
自分の識別子で検索すれば、当サービスの ID を保存する必要はありません。
GET /v1/agents/by-external-id/{chain_id}/{external_agent_id}
GET /v1/agents/by-erc8004/{chain_id}/{registry_address}/{erc8004_agent_id}
3つの API はいずれも、自分のプロジェクトに属さない ID に 404 を返します。「自分のものではない」と「存在しない」が同じレスポンスになるのは意図的な設計です。
4.2 コールバック(Webhook)
callback_url を指定すると、状態変更のたびに POST で通知します。
POST <指定した callback_url>
Content-Type: application/json
X-Callback-Token: <利用開始時に合意したトークン>
X-Callback-Token はプロジェクトの利用開始時に API キーとあわせて合意し、ID サービスの worker に設定されます。ID 作成のたびに新しく発行されるトークンではありません。受信側では、利用開始時に受け取った同じ値で検証してください。
{
"identity_id": "idn_c39e39dd-1030-4c33-b888-5beeb876247d",
"external_agent_id": "自分の-agent-id",
"chain_id": 677,
"status": "REGISTERED",
"wallet_binding_status": "CONFIRMED",
"erc8004_agent_id": "45",
"registry_address": "0xb43edfb9c7609cf645e932b2ff20f26f0d4488de",
"metadata_uri": "https://…/v2-….json",
"updated_at": "2026-09-08T06:12:51Z"
}
受信側は次の4つを守ってください。
- 最初に
X-Callback-Tokenを検証し、定数時間比較で一致を確認してから本文を処理します。この検証を省くと、URL を知る誰もが状態更新を偽造できます。 - 速やかに
2xxを返します。 それ以外は失敗として再試行されます。実際の処理は非同期で実行してください。 - 重複配信に対応します。 同じ状態が複数回届く可能性があるため、
identity_idとupdated_atを冪等キーにすれば十分です。 - 再試行で順序が前後することがあります。 保存済みレコードより
updated_atが古いペイロードは無視します。
再試行の間隔は15秒、1分、5分、その後は15分ごとです。配信は打ち切られません。 長期間失敗するエンドポイントでは、状態変更が破棄されるのではなく再試行が蓄積します。コールバックはポーリングを効率化するもので、代替ではありません。エンドポイントが1時間停止していても、ポーリングですぐに現在の状態を取得できます。
5. 説明情報の更新
PUT /v1/agents/identities/{identity_id}/metadata
X-API-Key: ak_…
{
"metadata": { "name": "サンプル Agent", "description": "更新後の説明" },
"idempotency_key": "update-2026-09-08-1"
}
登録ファイルの新しい版を公開し、オンチェーン URI を更新します。202 と {"identity": …, "replayed": false} を返し、同じ冪等キーで再送すると 200 と "replayed": true を返します。
受け付け後、ID の status は METADATA_PENDING に戻り、setAgentURI の確定後に REGISTERED になります。metadata_uri の変化、または status が REGISTERED に戻ることで反映を確認できます。
ここでは agentId、owner、walletAddress、registrations を指定できません。これらはオンチェーンで決まる値です。サービスが最新のオンチェーン値を各版に組み込むため、任意の owner や agentId を所有すると主張するファイルを公開することはできません。
ウォレット紐付けのリクエスト
POST /v1/agents/identities/{identity_id}/wallet-binding
Content-Type: application/json
X-API-Key: ak_…
{ "idempotency_key": "bind-2026-09-08-1" }
本文には冪等キーのみを指定します。アドレスや署名は不要です。ウォレットは ID 作成時に確定しており、オンチェーンの認可署名はウォレットの鍵を保有する当サービス側が生成します。
ID を作成しても紐付けは自動でキューに入りません。 ID の status が REGISTERED になってから、この API を呼び出してください。早すぎる呼び出しには 425 が返ります。初回の紐付けと、PENDING のままの紐付けを再度キューへ入れる場合の両方に使います。202、または 200 と "replayed": true を返します。
wallet_binding_status が CONFIRMED になると完了です。
一時停止
POST /v1/agents/identities/{identity_id}/suspend
X-API-Key: ak_…
200 と {"identity": …} を返します。一時停止した ID は、新たな登録ステップ、メタデータ更新、ウォレット紐付けなどの新しいタスクを受け付けず、suspended_at が設定されます。すでにブロードキャストされたトランザクションの確定処理は続行します。
オンチェーン ID には影響しません。一時停止はプラットフォーム側の状態であり、オンチェーン操作ではないため、第三者がレジストリを読むと引き続き有効な ID が表示されます。
6. エラー処理
エラー本文には error 文字列が含まれます。再試行の判断には HTTP ステータスを使います。
| ステータス | 意味 | 再試行? |
|---|---|---|
400 | リクエスト形式不正、または必須フィールド不足 | いいえ。リクエストを修正 |
401 | API キー未指定または無効 | いいえ |
404 | ID が存在しない、または別プロジェクトに所属 | いいえ |
409 | 別の ID がすでに wallet_id を使用している場合などの永続的な競合 | いいえ |
425 | ID が必要な状態にまだ到達していない | はい。後で再試行 |
5xx | サービス側のエラー | はい。バックオフ後に再試行 |
425 Too Early に注意してください。操作自体は有効でも、ID がその操作を実行できる段階に達していないことを意味します。例えば登録完了前のウォレット紐付けです。形式は 409 と似ていますが、意味は逆です。409 は中止、425 は後で再試行です。 425 を永続的な失敗と扱うと、成功できる ID を途中で放棄してしまいます。
7. オンチェーンで ID を検証する
ここまでの内容は、当サービスの API が当サービスの記録を説明するものです。ERC-8004 の価値は、第三者が当サービスを信頼せずに重要な情報を確認できる点にあります。Agent の所有を証明するよう求められたら、本節を相手に提示してください。
以下はすべて読み取り専用です。秘密鍵、ガス、アカウントは不要です。
7.1 主要な3つの読み取り
| 確認したいこと | 呼び出し | 戻り値 |
|---|---|---|
| Agent の制御者 | ownerOf(uint256 agentId) | address |
| 使用するウォレット | getAgentWallet(uint256 agentId) | address |
| 説明情報の場所 | tokenURI(uint256 agentId) | string |
import { ethers } from 'ethers'
const provider = new ethers.JsonRpcProvider('https://rpc.botchain.ai')
const registry = new ethers.Contract(
'0xB43Edfb9C7609cF645e932B2fF20f26F0d4488dE',
[
'function ownerOf(uint256) view returns (address)',
'function getAgentWallet(uint256) view returns (address)',
'function tokenURI(uint256) view returns (string)',
],
provider,
)
const agentId = 45n
console.log(await registry.ownerOf(agentId)) // 0x5f5802fA78d5eE2A3B4fD67F49CD502430C3E88C
console.log(await registry.getAgentWallet(agentId)) // 0xd9DC4F46d9da603A2A077A7190BAa85f4e2f05fe
console.log(await registry.tokenURI(agentId)) // https://…/v2-….json
依存ライブラリを追加したくない場合は、JSON-RPC を直接使えます。
# ownerOf(45)、セレクター 0x6352211e、引数を32バイトにパディング
curl -s https://rpc.botchain.ai \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"eth_call","params":[{
"to":"0xB43Edfb9C7609cF645e932B2fF20f26F0d4488dE",
"data":"0x6352211e000000000000000000000000000000000000000000000000000000000000002d"
},"latest"]}'
例はメインネットに接続しています。テストネットでは https://rpc.bohr.life と第8節の IdentityRegistry アドレスに変更してください。それ以外は同じです。
次の2点に注意してください。
- 未登録の ID に対する
ownerOfは、ゼロアドレスを返すのではなく revert します。この revert は「Agent が存在しない」と扱い、ネットワークエラーと区別してください。 getAgentWalletは ID の存在を検証しません。未登録の ID と、登録済みでもウォレット未紐付けの ID の両方でゼロアドレスを返します。存在確認にはgetAgentWalletではなくownerOfを使ってください。
7.2 登録ファイル
tokenURI は ERC-8004 登録ファイル形式の JSON を指します。
{
"type": "https://eips.ethereum.org/EIPS/eip-8004#registration-v1",
"name": "サンプル Agent",
"description": "この Agent の役割",
"owner": "0x5f5802fa78d5ee2a3b4fd67f49cd502430c3e88c",
"walletAddress": "0xd9dc4f46d9da603a2a077a7190baa85f4e2f05fe",
"registrations": [
{
"agentId": "45",
"agentRegistry": "eip155:677:0xb43edfb9c7609cf645e932b2ff20f26f0d4488de"
}
]
}
ファイルを信頼せず、検証してください。 tokenURI 以外から取得した URL にあるファイルは証明になりません。正しい手順は以下のとおりです。
- レジストリから
tokenURI(agentId)を取得します。 - 別の URL に置き換えず、その URL を取得します。
registrations[0].agentIdが対象 ID と一致し、registrations[0].agentRegistryが問い合わせたレジストリを指しているか確認します。ownerがownerOf、walletAddressがgetAgentWalletと一致するか確認します。
ファイルとチェーンが食い違う場合はチェーンを優先します。所有権とウォレット紐付けの正当な情報源はレジストリであり、ファイルはその内容と一致すべき説明にすぎません。
7.3 時間とともに変わる情報
| 変更 | オンチェーンメソッド | 再取得する値 |
|---|---|---|
| 説明情報の更新 | setAgentURI | tokenURI |
| ウォレットの紐付け・変更 | setAgentWallet | getAgentWallet |
| ウォレット紐付け解除 | unsetAgentWallet | getAgentWallet |
| 所有権の移転 | transferFrom | ownerOf |
URI は変わるため、登録ファイルを無期限にキャッシュしないでください。URI をキャッシュキーとし、最新情報が必要なときは tokenURI を再取得します。
ウォレット紐付けは2種類の署名検証に対応しているため、次のどちらのアカウントでも利用できます。
| ウォレット種別 | 検証方法 |
|---|---|
| EIP-7702 で委任された EOA を含む EOA | ECDSA |
| コントラクトウォレット(ERC-4337 アカウント、Safe など) | ERC-1271 |
Agent ウォレットは通常 EOA ではなくスマートアカウントなので、この点が重要です。
8. 環境とコントラクトアドレス
常にプロキシ(proxy)のアドレスを呼び出してください。実装コントラクトのアドレスはアップグレード時に変わります。
ID サービスが現在実行するのは、IdentityRegistry の登録、URI 更新、ウォレット紐付けのみです。以下の Reputation / Validation アドレスは、オンチェーンにデプロイ済みの ERC-8004 関連コントラクトですが、本サービスからは現在呼び出していません。第三者が独自に評判や検証の処理を連携する際に参照できます。ID 登録自体には IdentityRegistry のみが必要です。
BOT メインネット(chain ID 677)
| 項目 | アドレス |
|---|---|
| RPC | https://rpc.botchain.ai |
| ブロックエクスプローラー | https://scan.botchain.ai |
IdentityRegistry | 0xB43Edfb9C7609cF645e932B2fF20f26F0d4488dE |
ReputationRegistry | 0xB3f7061354193a424856Cc63028cE3556262dAc9 |
ValidationRegistry | 0x85Bf081D1492393C3Fb2742b379b6ADbC7dbC79b |
Bohr テストネット(chain ID 968)
| 項目 | アドレス |
|---|---|
| RPC | https://rpc.bohr.life |
| ブロックエクスプローラー | https://scan.bohr.life |
IdentityRegistry | 0xec8fFbC3c9A34AdDCbB3A14F91db2bd26A8b99c0 |
ReputationRegistry | 0xD4084c9397adca7fD0c24617681a2eA4C286402A |
ValidationRegistry | 0x0ff64E68C0e5fB2c57E6B3e1D7F3c65FBD0eEA33 |
agentId はレジストリごとに採番されます。メインネットの Agent 45 とテストネットの Agent 45 は無関係です。agentId を渡すときは必ず chain ID も含めてください。登録ファイルの agentRegistry はそのためにあります。
レジストリは完全な ERC-721 実装で、名称は AgentIdentity(AGENT)です。バージョンは一般的な version() ではなく、コントラクトの getVersion() で取得してください。現在は両チェーンとも 2.0.0 です。そのため、NFT 表示に対応したウォレットやエクスプローラーは、追加対応なしで Agent ID を表示できます。