OpenSea Tool SDK - SDK de Herramientas OpenSea
Construye, registra y protege endpoints de herramientas invocables por IA utilizando el Registro de Herramientas de OpenSea (ERC-8257) en Base.
Cuándo usar esta habilidad (scope_in)
Usa opensea-tool-sdk cuando necesites:
- Crear un endpoint de herramienta invocable por IA (HTTPS, JSON Schema, manifiesto
.well-known) para Vercel, Cloudflare o Express - Registrar una herramienta en cadena en el ToolRegistry de Base para que otros agentes puedan descubrirla
- Proteger el acceso mediante pago por llamada x402 (USDC) o predicados (propiedad de ERC-721/ERC-1155, suscripciones, gating por atributos, balance de ERC-20, compuestos)
- Llamar a una herramienta protegida o de pago: pagos 402 (
paidFetch), autenticación por predicado (eip3009AuthenticatedFetch), o ambos (paidAuthenticatedFetch) - Buscar y descubrir herramientas registradas a través de la API REST de OpenSea
Cuándo NO usar esta habilidad (scope_out, transferencia)
| Necesidad | Usa en su lugar |
|---|---|
| Consultar datos de NFT/tokens, búsqueda, estadísticas de colecciones | opensea-api |
| Comprar/vender NFTs | opensea-marketplace |
| Intercambiar tokens ERC20 | opensea-swaps |
| Configurar proveedores de firma de cartera | opensea-wallet |
Este SDK es para proveedores y consumidores de herramientas. Para consultar datos del marketplace de OpenSea (precios mínimos, listados, transacciones), usa la habilidad opensea-api.
Conceptos
| Término | Significado |
|---|---|
| Herramienta | Un único endpoint de API REST con una interfaz JSON Schema, descubrible mediante /.well-known/ai-tool/<slug>.json. Cada herramienta debe realizar una operación enfocada. |
| Manifiesto | JSON canonizado JCS que describe el nombre, endpoint, entradas, salidas, precio y política de acceso de la herramienta |
| ToolRegistry | Contrato en cadena (Base) donde se registran las herramientas con un hash del manifiesto y un predicado de acceso opcional |
| Predicado de Acceso | Un contrato IAccessPredicate que controla quién puede invocar una herramienta (propiedad de NFT, suscripciones, gating por atributos, balance de ERC-20, compuestos) |
| x402 | Protocolo de pago por llamada basado en HTTP 402 (quien llama firma una TransferWithAuthorization de USDC; el servidor liquida después de la ejecución) |
| Autenticación EIP-3009 | Firma TransferWithAuthorization de USDC de valor cero utilizada para autenticar a los llamantes de herramientas protegidas por predicado |
| Facilitador | Servicio de terceros que verifica y liquida pagos x402 (PayAI o Coinbase CDP) |
Restricciones Importantes
Una herramienta = un endpoint. Cada registro de herramienta representa un único endpoint de API REST con un enfoque e intención singular. La URL del endpoint en tu manifiesto debe apuntar a una ruta de API específica que realice una operación bien definida (por ejemplo, POST /api/price-check o POST /api/translate), no a una página HTML genérica, un sitio de documentación o una URL de propósito múltiple. Piensa en cada herramienta registrada de la misma manera que piensas en un endpoint de API REST individual. Debe aceptar una entrada específica, realizar una acción específica y devolver una salida específica.
Vinculación de origen: el manifiesto y el endpoint deben compartir el mismo origen exacto. Tu manifiesto /.well-known/ai-tool/<slug>.json y el endpoint de invocación de tu herramienta deben servirse desde exactamente el mismo origen (esquema, host y puerto idénticos según RFC 6454). Los subdominios no cuentan como el mismo origen. example.com y api.example.com son orígenes diferentes. Esto se aplica en el momento del registro. Si el origen del manifiesto y el origen del endpoint no coinciden exactamente, la herramienta será rechazada y marcada como no registrada.
- Válido: manifiesto en
https://my-tool.example.com/.well-known/ai-tool/my-tool.json, endpoint enhttps://my-tool.example.com/api/my-tool - Inválido: manifiesto en
https://example.com/.well-known/ai-tool/my-tool.json, endpoint enhttps://api.example.com/api/my-tool
Si necesitas tu API en un subdominio, sirve el manifiesto desde ese mismo subdominio (por ejemplo, ambos en api.example.com).
Contratos Desplegados (Ethereum mainnet, Base, Shape, Abstract, Monad, Robinhood Chain)
Despliegues canónicos v0.2 — dirección CREATE2 idéntica en cada cadena compatible.
| Contrato | Dirección |
|---|---|
| ToolRegistry (v0.2) | 0x265BB2DBFC0A8165C9A1941Eb1372F349baD2cf1 |
| ERC721OwnerPredicate (v0.2) | 0xc8721c9A776958FfFfEb602DA1b708bf1D318379 |
| ERC1155OwnerPredicate (v0.2) | 0x77373Dc3c1AE9A1e937eF3e5E08F4807D47c7c11 |
| SubscriptionPredicate (v0.2) | 0xCBe0cd9B1d99d95Baa9c58f2767246C52e461f25 |
| TraitGatedPredicate (v0.2) | 0x10abF07CfA34Bf22372C57f27e8bd9C2DCF93fA1 |
| ERC20BalancePredicate (v0.2) | 0x1a834FC48B5f6e119c62C12a98b32137bCFA77cD |
Descubrimiento de Herramientas [Beta]
Busca o consulta herramientas registradas a través de la API REST de OpenSea. Requiere OPENSEA_API_KEY.
# Reutiliza OPENSEA_API_KEY si ya está configurada; de lo contrario, obtén una clave instantánea gratuita
# (sin registro — 600/h de lectura, 30/h de escritura, caducidad de 7 días) y GUÁRDALA para reutilizarla.
if [ -z "${OPENSEA_API_KEY:-}" ]; then
KEY_FILE="${OPENSEA_CONFIG_DIR:-$HOME/.opensea}/api_key"
if [ -s "$KEY_FILE" ]; then
export OPENSEA_API_KEY=$(cat "$KEY_FILE") # reutilizar clave en caché
else
api_key=$(curl -s -X POST https://api.opensea.io/api/v2/auth/keys | jq -r '.api_key')
mkdir -p "$(dirname "$KEY_FILE")"
(umask 077; printf '%s\n' "$api_key" > "$KEY_FILE") # guardar antes de usarla
export OPENSEA_API_KEY="${api_key}"
fi
fi
Siempre guarda una clave instantánea obtenida y reutilízala en lugar de volver a obtenerla. La habilidad opensea-api incluye un helper auth/opensea-resolve-key.sh que hace esto (env → archivo en caché → obtener + guardar); consulta su sección "Resolución de clave API". Para límites de velocidad más altos, crea una clave completa en Configuración → Desarrollador.
Listar herramientas: GET /api/v2/tools (docs)
| Parámetro | Requerido | Descripción |
|---|---|---|
sort_by | No | Ordenar por: newest (predeterminado), oldest |
type | No | Filtrar por tipo de acceso: open, nft_gated, token_gated, subscription, gated |
limit | No | Resultados por página (1–100) |
cursor | No | Cursor de paginación |
Buscar herramientas: GET /api/v2/tools/search (docs)
| Parámetro | Requerido | Descripción |
|---|---|---|
query | No | Texto de consulta de búsqueda |
registry_chain | No | Filtrar por ID de cadena del registro |
tags | No | Filtrar por etiquetas |
access_type | No | Filtrar por tipo de acceso: open, nft_gated, subscription |
creator | No | Filtrar por dirección del creador |
sort_by | No | Ordenar por: relevance (predeterminado), newest, most_used |
limit | No | Resultados por página (1–200) |
cursor.value | No | Cursor de paginación |
Obtener una herramienta: GET /api/v2/tools/{registry_chain}/{registry_addr}/{tool_id} (docs)
| Parámetro | Requerido | Descripción |
|---|---|---|
registry_chain | Sí | ID de cadena del registro (ej. 1, 8453) |
registry_addr | Sí | Dirección del contrato del registro |
tool_id | Sí | ID numérico de la herramienta |
# Listar herramientas ordenadas por las más nuevas
curl -s "https://api.opensea.io/api/v2/tools?sort_by=newest&limit=10" \
-H "x-api-key: $OPENSEA_API_KEY" | jq
# Listar herramientas filtradas por tipo
curl -s "https://api.opensea.io/api/v2/tools?type=open&sort_by=oldest" \
-H "x-api-key: $OPENSEA_API_KEY" | jq
# Buscar herramientas por palabra clave
curl -s "https://api.opensea.io/api/v2/tools/search?query=nft" \
-H "x-api-key: $OPENSEA_API_KEY" | jq
# Obtener una herramienta específica en Base
curl -s "https://api.opensea.io/api/v2/tools/8453/0x265BB2DBFC0A8165C9A1941Eb1372F349baD2cf1/1" \
-H "x-api-key: $OPENSEA_API_KEY" | jq
# Filtrar por tipo de acceso
curl -s "https://api.opensea.io/api/v2/tools/search?access_type=open&limit=10" \
-H "x-api-key: $OPENSEA_API_KEY" | jq
1. Crear una Herramienta
1a. Crear un proyecto
npx @opensea/tool-sdk init --runtime vercel # o: cloudflare, express
Esto genera:
src/manifest.ts— definición del manifiesto de la herramientasrc/handler.ts— manejador de solicitudes con esquemas de entrada/salidaapi/index.ts— punto de entrada del adaptador del frameworkpublic/llms.txt— página de descubrimiento legible por agentesapi/well-known/[slug].ts— sirve el manifiesto en/.well-known/ai-tool/<slug>.json
1b. Definir el manifiesto
import { defineManifest } from "@opensea/tool-sdk"
export const manifest = defineManifest({
name: "Mi Herramienta",
description: "Qué hace esta herramienta",
endpoint: "https://my-tool.example.com/api",
creatorAddress: "0xYOUR_WALLET_ADDRESS",
inputs: {
type: "object",
properties: {
query: { type: "string", description: "Consulta de búsqueda" },
},
required: ["query"],
},
outputs: {
type: "object",
properties: {
result: { type: "string" },
},
},
// Opcional: añadir precio para el muro de pago x402 (consulta references/x402.md)
// pricing: paywall.pricing,
// Opcional: añadir requisitos de acceso (consulta references/predicate-gating.md)
// access: { logic: "OR", requirements: [...] },
})
1c. Escribir el manejador
import { createToolHandler } from "@opensea/tool-sdk"
import { z } from "zod/v4"
import { manifest } from "./manifest.js"
const InputSchema = z.object({ query: z.string() })
const OutputSchema = z.object({ result: z.string() })
export const toolHandler = createToolHandler({
manifest,
inputSchema: InputSchema,
outputSchema: OutputSchema,
// gates: [], // Añadir compuertas aquí (consulta references/x402.md y references/predicate-gating.md)
handler: async (input) => {
return { result: `Procesado: ${input.query}` }
},
})
1d. Conectar el adaptador
Vercel:
import { toVercelHandler } from "@opensea/tool-sdk"
import { toolHandler } from "../src/handler.js"
export default toVercelHandler(toolHandler)
Express:
import { toExpressHandler } from "@opensea/tool-sdk"
import { toolHandler } from "./handler.js"
app.post("/api", toExpressHandler(toolHandler))
Cloudflare Workers:
import { toolHandler } from "./handler.js"
export default { fetch: toolHandler }
2. Registrar una Herramienta en Cadena
2a. Mediante CLI
# Configurar cartera
export PRIVATE_KEY=0x...
export RPC_URL=https://mainnet.base.org
# Registrar (acceso abierto — sin predicado)
npx @opensea/tool-sdk register \
--metadata https://my-tool.example.com/.well-known/ai-tool/my-tool.json \
--network base
# Registrar con un predicado de acceso
npx @opensea/tool-sdk register \
--metadata https://my-tool.example.com/.well-known/ai-tool/my-tool.json \
--network base \
--access-predicate 0xPREDICATE_ADDRESS
# Simulación (sin transacción)
npx @opensea/tool-sdk register --metadata ... --network base --dry-run
La CLI:
- Obtiene el manifiesto desde la URL
--metadata - Valida el esquema del manifiesto
- Verifica que
manifest.creatorAddresscoincida con tu cartera - Calcula el hash del manifiesto JCS keccak256
- Llama a
ToolRegistry.registerTool(metadataURI, manifestHash, accessPredicate) - Devuelve el
toolIddel eventoToolRegistered
2b. Mediante SDK (programático)
import { ToolRegistryClient, computeManifestHash } from "@opensea/tool-sdk"
import { createWalletFromEnv, walletAdapterToClient } from "@opensea/tool-sdk"
import { base } from "viem/chains"
const adapter = createWalletFromEnv()
const walletClient = await walletAdapterToClient(adapter, base)
const registry = new ToolRegistryClient({
chain: base,
rpcUrl: "https://mainnet.base.org",
walletClient,
})
const { toolId, txHash } = await registry.registerTool({
metadataURI: "https://my-tool.example.com/.well-known/ai-tool/my-tool.json",
manifest, // tu objeto ToolManifest
accessPredicate: "0x0000...0000", // address(0) = acceso abierto
})
console.log(`Herramienta registrada ${toolId} en tx ${txHash}`)
3. Proteger el Acceso a las Herramientas
Las herramientas se pueden proteger de tres maneras:
| Compuerta | Mecanismo | Referencia |
|---|---|---|
| Muro de pago x402 | Pago por llamada (USDC, EIP-3009) | references/x402.md |
| Compuerta de predicado | Verificación en cadena (NFT, suscripción, gating por atributos, balance ERC-20, compuesto) | references/predicate-gating.md |
| Combinado | Autenticación EIP-3009 y pago (primero predicado, luego x402) | references/predicate-gating.md |
Para direcciones de predicados desplegados, codificaciones de requisitos y ayudantes del SDK como describeToolAccess / decodeRequirement, consulta references/known-predicates.md.
4. Configuración de Cartera
El SDK admite múltiples proveedores de cartera a través de @opensea/wallet-adapters. Configura las variables de entorno y el SDK detecta automáticamente el proveedor. Consulta la habilidad opensea-wallet para obtener la tabla completa de proveedores, variables de entorno, guías de configuración y configuración de políticas de firma.
| Proveedor | Variables de entorno | Mejor para |
|---|---|---|
| Clave Privada | PRIVATE_KEY | Desarrollo local, scripts |
| Privy | PRIVY_APP_ID, PRIVY_APP_SECRET, PRIVY_WALLET_ID | Carteras de servidor |
| Turnkey | TURNKEY_API_PUBLIC_KEY, TURNKEY_API_PRIVATE_KEY, TURNKEY_ORGANIZATION_ID | Firma empresarial |
| Fireblocks | FIREBLOCKS_API_KEY, FIREBLOCKS_API_SECRET, FIREBLOCKS_VAULT_ACCOUNT_ID | Custodia institucional |
| Bankr | BANKR_API_KEY | Carteras de agente (a través de API HTTP) |
Para cualquier proveedor, RPC_URL (o la bandera --rpc-url) establece el endpoint RPC para lecturas y escrituras en cadena. Cuando no se establece ninguno, los comandos CLI recurren al RPC público predeterminado de la red, que puede ser lento o tener límite de velocidad.
import { createWalletFromEnv } from "@opensea/tool-sdk"
// Auto-detección: Privy > Fireblocks > Turnkey > Bankr > Clave Privada
const adapter = createWalletFromEnv()
const address = await adapter.getAddress()
Para Bankr (firmante externo):
import { createBankrAccount } from "@opensea/tool-sdk"
const account = await createBankrAccount("tu-clave-api-bankr")
// Usar con eip3009AuthenticatedFetch o paidAuthenticatedFetch
5. Respuesta
... [truncado para traducción]