Agent Tool Registry (ERC-8257)
Build, register, and gate AI agent tools onchain using the ERC-8257 Tool Registry.
Don't have an onchain agent? Set one up.
ERC-8257 defines a permissionless onchain registry for AI agent tools. Any developer can register a tool, gate access with an onchain predicate (NFT ownership, subscriptions, allowlists, or custom logic), and optionally charge per call using x402 micropayments, all without a centralized platform.
How It Works
A tool is a single-purpose HTTPS endpoint with a JSON Schema interface, discoverable through a .well-known manifest. Each tool registration should map to exactly one REST API endpoint that performs a focused action, similar to how a well-designed REST API has one endpoint per operation. The lifecycle:
- Build an endpoint that accepts JSON input and returns JSON output, then serve a manifest at
/.well-known/ai-tool/<slug>.json. - Register it by calling
registerToolon the onchain registry with your manifest URI and its keccak256 hash. The registry assigns atoolId. - Gate it (optional) by attaching an access predicate contract that controls who can invoke the tool, or leave it as
address(0)for open access.
+-----------------+ +---------------------+ +-----------+
| PUBLISHER |---->| TOOL REGISTRY |<----| AGENT |
| | | | | |
| serves manifest | | | | discovers |
| + handler | | creator | | verifies |
| | | metadataURI | | checks |
| | | manifestHash | | access |
| | | accessPredicate | | invokes |
+-----------------+ +---------------------+ +-----------+
Agents discover tools by reading the registry, verify the manifest hash, check access via the predicate, and invoke the endpoint.
Key Concepts
| Term | Description |
|---|---|
| Tool | A single REST API endpoint with a JSON Schema interface, discoverable via /.well-known/ai-tool/<slug>.json. Each tool should perform one focused operation. |
| Manifest | JCS-canonicalized JSON describing name, endpoint, inputs, outputs, pricing, and access policy |
| Access Predicate | An IAccessPredicate contract that gates who can invoke a tool (NFT ownership, subscriptions, traits, composites, or any custom logic) |
| x402 | HTTP 402-based pay-per-call protocol using USDC TransferWithAuthorization |
| EIP-3009 auth | Zero-value USDC TransferWithAuthorization signature for authenticating callers |
One tool = one endpoint. Each tool registration represents a single REST API endpoint with a singular focus and intention. The endpoint URL in your manifest should point to a specific API route that performs one well-defined operation (e.g.,POST /api/price-checkorPOST /api/translate), not a generic HTML page, documentation site, or multi-purpose URL. Think of each registered tool the same way you think of an individual REST API endpoint. It should accept a specific input, perform a specific action, and return a specific output.
Origin binding: manifest and endpoint must share the exact same origin. Your.well-known/ai-tool/<slug>.jsonmanifest and your tool's invocation endpoint must be served from the exact same origin. That means identical scheme, host, and port per RFC 6454. Subdomains do not count as the same origin.example.comandapi.example.comare different origins. This is enforced at registration time. If the manifest origin and endpoint origin don't match exactly, the tool will be rejected and marked as deregistered.✅ Valid (manifest and endpoint on the same host):
- Manifest:
https://my-tool.example.com/.well-known/ai-tool/my-tool.json- Endpoint:
https://my-tool.example.com/api/my-tool❌ Invalid (manifest on apex domain, endpoint on subdomain):
- Manifest:
https://example.com/.well-known/ai-tool/my-tool.json- Endpoint:
https://api.example.com/api/my-toolIf you need your API on a subdomain, serve the manifest from that same subdomain (e.g., both on
api.example.com).
Quick Start
The @opensea/tool-sdk handles the whole lifecycle: scaffold, deploy, register, gate, and call tools.
# 1. Scaffold a new tool (generates manifest, handler, adapter, and .well-known route)
npx @opensea/tool-sdk init my-tool --runtime vercel
cd my-tool && npm install
# 2. Edit src/manifest.ts and src/handler.ts with your logic
# 3. Deploy
npx @opensea/tool-sdk deploy
# 4. Register onchain (configure a wallet provider, see the SDK README)
# Supports: Privy, Turnkey, Fireblocks, Bankr, or a local private key
# 4a. Open access (no gate)
npx @opensea/tool-sdk register \
--metadata https://my-tool.vercel.app/.well-known/ai-tool/my-tool.json \
--network base
# 4b. NFT-gated access
npx @opensea/tool-sdk register \
--metadata https://my-tool.vercel.app/.well-known/ai-tool/my-tool.json \
--network base \
--nft-gate 0xCOLLECTION_ADDRESSSee the Tool SDK README for the full CLI reference, handler examples, adapter setup (Vercel, Cloudflare, Express), wallet providers, and predicate configuration.
Tool Manifest
The manifest served at /.well-known/ai-tool/<slug>.json describes your tool's capabilities, endpoint, inputs, outputs, and display metadata. Key points:
image: a square (1:1) icon shown as the thumbnail in search results and tool cards.featuredImage: a 16:9 banner image. Including one is required for consideration on the featured section of the Tools homepage.tags: discovery tags used for search and category filtering (supported categories:ai,defi,nft,trading,image,security).
See the Tool Manifest field reference for the complete schema, all required and optional fields, category tag details, and example manifests.
Access Control
Access control is extensible: any contract that implements IAccessPredicate can gate a tool:
interface IAccessPredicate {
function hasAccess(uint256 toolId, address account, bytes calldata data) external view returns (bool);
function name() external view returns (string memory);
}The Tool Registry repo includes reference predicate implementations for common access patterns: NFT ownership (ERC-721/1155), subscriptions, trait gating, pay-per-call (x402), and composite logic. See the repo for deployed addresses and supported chains.
Tool Invocation Flow
Both free (predicate-gated) and paid (x402) tools use a unified 402 challenge-response pattern. The caller never pre-computes auth; the server tells it what to sign.
CALLER TOOL SERVER
| |
| 1. POST /tool (no auth) |
|-------------------------------->|
| |
| 2. 402 + PaymentRequirements |
|<--------------------------------|
| |
| 3. Sign X-Payment (EIP-3009) |
| |
| 4. POST /tool + X-Payment hdr |
|-------------------------------->|
| |
| 5. Verify signature (ecrecover)|
| 6. Check access predicate |
| 7. Execute handler |
| |
| 8. 200 + tool output |
|<--------------------------------|
| |
Step-by-step
| Step | Description |
|---|---|
| 1. Initial request | Caller sends a plain POST with no Authorization or X-Payment header. |
| 2. 402 challenge | Server returns 402 with a body containing accepts: [{ scheme, network, payTo, maxAmountRequired, asset }]. For free tools maxAmountRequired is "0"; for paid tools it is the USDC price. |
| 3. Sign X-Payment | Caller signs an EIP-3009 TransferWithAuthorization (EIP-712 typed data in the USDC domain) using payTo and maxAmountRequired from the challenge. The signature is wrapped into a PaymentPayload and base64-encoded. |
| 4. Retry with header | Caller replays the request with X-Payment: <base64(PaymentPayload)>. |
| 5. Verify | Server decodes and verifies the signature via pure ecrecover, with no RPC needed. Asserts to == operatorAddress (domain binding) and checks TTL. |
| 6. Access check | Server calls tryHasAccess(toolId, callerAddress, data) on the onchain registry. Returns 403 if granted: false. |
| 7. Execute | Handler runs if access is granted. For paid tools, the x402 facilitator settles payment onchain after the predicate check passes. If access is denied, no funds move. |
| 8. Response | Tool output returned as JSON. |
X-Payment payload structure
{
"x402Version": 1,
"scheme": "exact",
"network": "base",
"payload": {
"signature": "0x...",
"authorization": {
"from": "0xCALLER",
"to": "0xOPERATOR",
"value": "0 (free) or amount in base units (paid)",
"validAfter": "0",
"validBefore": "1749158400",
"nonce": "0x<random-32-bytes>"
}
}
}The to field is always the payTo address from the 402 challenge: the tool operator for free tools, or the payment recipient for paid tools. This prevents cross-tool signature replay.
Combined predicate + payment
Tools that require both an access predicate and x402 payment use the SDK's paidPredicateGate, a single gate that resolves identity and payment in one 402 round trip. The 402 challenge advertises the real USDC price (not zero). The caller's X-Payment signature for the real amount simultaneously proves identity (via the recovered from address) and authorizes payment. The onchain predicate is checked before the facilitator settles, so if the caller lacks access a 403 is returned and no funds move.
Usage Reporting
After a tool invocation completes, the Tool SDK reports usage to the OpenSea API before returning the response. The report is awaited so it survives serverless runtimes (Vercel, Lambda) where the function freezes once the response flushes. Errors are caught and logged but never turn a successful tool call into a failure.
POST https://api.opensea.io/api/v2/tools/usage
x-api-key: <api-key>
Tool identification
The report identifies the tool using one of two approaches:
- ERC-8257 composite key (preferred for server-side reporters): provide
tool_chain_id,tool_registry_address, andtool_onchain_id. - Canonical endpoint URL: provide
tool_endpoint(the tool's registered URL). The backend resolves the onchain registry coordinates automatically. If multiple tools share the same endpoint, the request is rejected with a 400 asking for explicit coordinates.
Verification types
The report includes one of two verification types depending on the invocation path:
Free tools (predicate-gated): eip3009_authorization
eip3009_authorization{
"verification_type": "eip3009_authorization",
"tool_chain_id": 8453,
"tool_registry_address": "0x...",
"tool_onchain_id": "42",
"latency_ms": 120,
"eip3009": {
"caller_address": "0xCALLER",
"signature": "0x...",
"chain_id": 8453,
"from": "0xCALLER",
"to": "0xOPERATOR",
"value": "0",
"valid_after": "0",
"valid_before": "1749158400",
"nonce": "0x..."
}
}The caller's original zero-value EIP-3009 signature from the X-Payment header is forwarded as-is. The tool server never re-signs.
Paid tools (x402): x402_settlement
x402_settlement{
"verification_type": "x402_settlement",
"tool_chain_id": 8453,
"tool_registry_address": "0x...",
"tool_onchain_id": "42",
"latency_ms": 250,
"x402": {
"caller_address": "0xCALLER",
"tx_hash": "0x...",
"chain_id": 8453
}
}The settlement transaction hash from the x402 facilitator is included, enabling onchain payment verification.
Server-side reporting (tool operator)
The tool service reports usage automatically via the createEip3009UsageReporter factory. It identifies the tool by composite key and authenticates with the tool operator's API key. Both free (EIP-3009) and paid (x402) invocations are reported through this path.
Caller-side reporting (invoking agent)
Callers (e.g. the pay CLI command or an agent making authenticated requests) can also report usage independently. Caller-side reporters identify the tool by tool_endpoint so the caller does not need the onchain registry coordinates. If no API key is configured, the reporter auto-provisions one via POST /api/v2/auth/keys.
import { reportCallerX402Usage, reportCallerEip3009Usage } from "@opensea/tool-sdk"
// After an x402 payment settles
await reportCallerX402Usage({
toolEndpoint: "https://my-tool.example.com/api/run",
callerAddress: "0xCALLER",
txHash: "0x...",
chainId: 8453,
})If both the tool server and the caller report the same settlement, the second report is deduplicated (returns HTTP 400 with "already reported"). From the caller's perspective this counts as a success since the usage was recorded.
All usage reporters have a 5-second timeout. If the report fails or times out, the tool invocation still succeeds. Errors are logged but never propagated to the caller.
REST API: Tool Endpoints
The OpenSea API provides endpoints for discovering and retrieving registered tools, returning enriched data including NFT collection details (name, image, floor price) for predicate-gated tools.
List tools
List all registered tools with optional sorting and filtering:
curl "https://api.opensea.io/api/v2/tools?sort_by=newest&limit=10" \
-H "x-api-key: YOUR_API_KEY"See the List Tools API reference for all parameters and the full response schema.
Search tools
Find tools by keyword, tags, access type, creator, or chain:
curl "https://api.opensea.io/api/v2/tools/search?query=nft&limit=10" \
-H "x-api-key: YOUR_API_KEY"See the Search Tools API reference for all parameters and the full response schema.
Get a tool
Retrieve a specific tool by its registry chain, registry address, and tool ID:
curl "https://api.opensea.io/api/v2/tools/{chain}/{registry_address}/{tool_id}" \
-H "x-api-key: YOUR_API_KEY"See the Get Tool API reference for the full response schema.
Don't have an API key yet? See Instant API Key to grab one for free.
MCP & CLI
The Tool Registry endpoints are also available through the MCP Server (search_tools, get_tool) and the CLI:
# CLI: search, list, or get tools
opensea tools search --query "nft" --access-type open
opensea tools list --sort-by newest --limit 10
opensea tools get 8453 0xRegistryAddr 42Agent Skill
The OpenSea Agent Skill includes a dedicated sub-skill for building and registering tools. If you're using an AI coding assistant (Claude Code, Cursor, Windsurf, etc.):
npx skills add ProjectOpenSea/opensea-skillThen prompt: "Register an NFT-gated tool on Base", "Scaffold a new tool with x402 payments", etc.
Resources
| Resource | Description |
|---|---|
| Tool SDK | TypeScript SDK and CLI to build, register, gate, and call tools |
| Tool Registry | Solidity contracts, deployed addresses, and supported chains |
| ERC-8257 Specification | Full standard |
| 8257.ai | Interactive overview and walkthrough |
| List Tools [Beta] | List all registered tools with sorting and filtering |
| Search Tools [Beta] | Discover registered tools by keyword, tags, access type, or chain |
| Get Tool [Beta] | Retrieve a specific tool with enriched NFT collection data |
| OpenSea MCP Server | MCP tools for tool discovery: search_tools, get_tool |
| OpenSea CLI | CLI commands: opensea tools search, opensea tools list, opensea tools get |
| Build with AI Agents | Integrate OpenSea data into AI workflows |
| ERC-8257 Telegram | Community discussion |
