Back
Docsv0.1
Github

AgentsScan

API Documentation

On-chain identity for AI agents using ENS subnames and ENSIP-25 verification.

Overview

AgentsScan provides a way to register AI agents on-chain by issuing them ENS subnames, setting ENSIP-25 attestation text records, and making everything cryptographically verifiable. There are two ways to register an agent:

UI Flow

Connect your wallet, fill in the form, and sign transactions directly from the dashboard. Your wallet executes all 5 on-chain operations. No backend needed.

API / Relayer Flow

Sign an EIP-191 message off-chain, send it to the relayer API, and the server executes all on-chain operations on your behalf. Best for programmatic use.

Quick Start

01Clone and install

Clone the repository and install dependencies. The project uses Next.js 16, wagmi, viem, and Tailwind CSS.

bash
git clone https://gitlab.com/proskairos/agentsscan.git
cd agentsscan
npm install
02Set environment variables

Create a .env.local file in the project root with the following variables. You need a funded relayer wallet on Sepolia.

.env.local
# Relayer private key (funded with Sepolia ETH)
RELAYER_PRIVATE_KEY=0x_your_private_key_here

# WalletConnect Project ID (get from cloud.walletconnect.com)
NEXT_PUBLIC_WC_PROJECT_ID=your_project_id
03Run the dev server

Start the development server. The app runs on localhost:3000 by default.

bash
npm run dev

Architecture

The system has three key addresses that you should understand before using the API:

01Connected Wallet (You)

The ENS name owner. This wallet must own the parent ENS name (e.g. myname.eth). In the API flow, you sign an EIP-191 message to prove ownership. The relayer then acts on your behalf.

02Agent Wallet (The Agent's Address)

The ETH address that gets set as the ENS record for the subname. This is the on-chain identity of your AI agent. It can be the same as your connected wallet or a separate hot wallet the agent uses to transact.

03Relayer Wallet (Backend)

A server-side wallet defined by RELAYER_PRIVATE_KEY. This wallet executes all on-chain transactions in the API flow. It must be funded with Sepolia ETH and approved via setApprovalForAll on the ENS Registry by the ENS owner.

Environment Setup

Before using the API flow, there is one on-chain prerequisite you must complete: approve the relayer wallet to create subnodes under your ENS name.

Approve the Relayer (One-time Setup)

The relayer needs permission to call setSubnodeOwner on your parent ENS name. You must call setApprovalForAll(relayerAddress, true) on the ENS Registry contract. This only needs to be done once per ENS name.

!
Without this approval, the relayer will fail at Step 2a with a revert. You can do this from Remix, Etherscan, or any Web3 interface.
Etherscan / Remix call
// Target: ENS Registry
// Address: 0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e
// Function: setApprovalForAll(address operator, bool approved)
//
// operator:  <your relayer wallet address>
// approved:  true
ethers.js example
import { ethers } from "ethers";

const provider = new ethers.JsonRpcProvider(
  "https://ethereum-sepolia.publicnode.com"
);
const signer = new ethers.Wallet(PRIVATE_KEY, provider);

const ensRegistry = new ethers.Contract(
  "0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e",
  ["function setApprovalForAll(address,bool)"],
  signer
);

// Approve relayer to create subnodes under your name
const tx = await ensRegistry.setApprovalForAll(
  RELAYER_ADDRESS,   // the relayer wallet address
  true
);
await tx.wait();
console.log("Approved! Relayer can now create subnodes.");

API Reference

POST /api/register

Register a new AI agent via the relayer. The relayer verifies your EIP-191 signature against the on-chain ENS owner, then executes all 5 on-chain operations.

Request Body

bash
{
  "parentName":        "myname.eth",
  "sublabel":          "trader-bot",
  "agentWalletAddress": "0x1234...abcd",
  "signature":         "0xabcdef..."
}

Parameters

parentNamerequired

The parent ENS name you own. Must end with .eth.

sublabelrequired

The sublabel for the agent. The full ENS name will be {sublabel}.{parentName}.

agentWalletAddressrequired

The ETH address to set as the ENS record for this agent. Can be the same as the owner or a separate agent wallet.

signaturerequired

An EIP-191 signature of the message: I authorize registering {sublabel}.{parentName}. The signer must be the on-chain ENS owner.

Success Response (200)

bash
{
  "success": true,
  "ensName": "trader-bot.myname.eth",
  "agentId": 1,
  "relayer": "0xRE...AYER",
  "transactions": {
    "setSubnodeOwner":  "0xabc...",
    "setResolver":       "0xdef...",
    "setAddr":           "0x123...",
    "registerAgent":     "0x456...",
    "setEnsip25Text":    "0x789..."
  }
}

Error Response (4xx / 5xx)

bash
{
  "success": false,
  "error": "Missing required fields: parentName, sublabel, agentWalletAddress, signature"
}

Error Codes

400Invalid input, missing fields, or bad signature format.
403Signer is not the on-chain owner of the parent ENS name.
500Relayer not configured, contract not deployed, or on-chain transaction failed.

Testing the Flow

Here is a complete step-by-step guide to test the API flow end to end. This assumes you already have a funded wallet with a Sepolia ENS name.

Step 1: Get a Sepolia ENS name

Go to app.ens.domains, connect your wallet, switch to Sepolia, and register any available .eth name. This will be your parentName.

Step 2: Fund the relayer wallet

Generate a new wallet (or use an existing one), set it as RELAYER_PRIVATE_KEY in .env.local, and fund it with Sepolia ETH from a faucet.

Step 3: Approve the relayer

Call setApprovalForAll(relayerAddress, true) on the ENS Registry from your ENS owner wallet. See the Environment Setup section for details.

Step 4: Construct the signature message

The EIP-191 message must follow this exact format. The relayer will verify this message against the on-chain ENS owner.

Message format
I authorize registering {sublabel}.{parentName}

// Example:
I authorize registering trader-bot.myname.eth

Step 5: Sign the message

Sign the message from your ENS owner wallet using any Web3 library. Here are examples for both wagmi and ethers.js:

wagmi (React)
import { signMessage } from "wagmi/actions";

const parentName = "myname.eth";
const sublabel = "trader-bot";
const message = `I authorize registering ${sublabel}.${parentName}`;

const signature = await signMessage({ message });
// signature => "0xabcdef..."
ethers.js (Node.js)
import { ethers } from "ethers";

const signer = new ethers.Wallet(PRIVATE_KEY);
const message = "I authorize registering trader-bot.myname.eth";

const signature = await signer.signMessage(message);
// signature => "0xabcdef..."

Step 6: Send the API request

With the signature in hand, make a POST request to the relayer endpoint. The server will verify your signature, check ENS ownership, and execute all 5 on-chain operations.

JavaScript
const response = await fetch("/api/register", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    parentName:         "myname.eth",
    sublabel:           "trader-bot",
    agentWalletAddress: "0xYourAgentWalletAddress",
    signature:          "0xYourEip191Signature",
  }),
});

const data = await response.json();

if (data.success) {
  console.log("Agent registered!", data.ensName);
  console.log("Agent ID:", data.agentId);
  console.log("Transactions:", data.transactions);
} else {
  console.error("Failed:", data.error);
}
cURL
curl -X POST https://your-domain.com/api/register \
  -H "Content-Type: application/json" \
  -d '{
    "parentName": "myname.eth",
    "sublabel": "trader-bot",
    "agentWalletAddress": "0xYourAgentWallet",
    "signature": "0xYourEip191Sig"
  }'
โœ“
After a successful response, you can verify the agent on the dashboard Discover tab using the full ENS name (e.g. trader-bot.myname.eth).

Deployed Contracts

All contracts are deployed on Sepolia testnet. These addresses are configured in src/lib/wagmi.ts.

MinimalAgentRegistrydeployed

0x67D2c322F409B15f5e6e1Bd1d092fc71c1010AC8

Stores agent records with auto-incrementing IDs. Functions: registerAgent(string) returns uint256 ID, agents(uint256) returns (owner, ensName, exists).

ENS Registry (Sepolia)

0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e

The official Sepolia ENS registry. Used for setSubnodeOwner, setResolver, setApprovalForAll, and owner lookups.

Public Resolver (Sepolia)

0xE99638b40E4Fff0129D56f03b55b6bbC4BBE49b5

The official Sepolia public resolver. Used for setAddr, setText, and reading ENS text records for verification.

On-chain Steps

Registering an agent requires exactly 5 on-chain transactions, executed in order. Here is what each step does and why the order matters.

2asetSubnodeOwner

Takes ownership of the subnode (e.g. trader-bot.myname.eth) from the parent ENS owner. The new owner becomes the relayer address (API flow) or agent wallet address (UI flow). This must happen first because you need ownership to set resolver and records.

bash
// ENS Registry: setSubnodeOwner(node, label, owner)
// node   = namehash("myname.eth")
// label  = labelhash("trader-bot")
// owner  = relayerAddress (API) or agentWallet (UI)
2bsetResolver

Points the subnode to the Sepolia Public Resolver. This must be set before you can call setAddr or setText on the subname, because those functions are called on the resolver contract.

bash
// ENS Registry: setResolver(node, resolver)
// node     = namehash("trader-bot.myname.eth")
// resolver = 0xE99638b40E4Fff0129D56f03b55b6bbC4BBE49b5
2csetAddr

Sets the primary ETH address record for the agent subname. When someone resolves trader-bot.myname.eth, they get this address back. This is the agent's on-chain identity.

bash
// Public Resolver: setAddr(node, addr)
// node = namehash("trader-bot.myname.eth")
// addr = 0xYourAgentWalletAddress
2dregisterAgent

Calls the MinimalAgentRegistry contract to create a new agent record. The contract auto-assigns an incrementing ID and stores the ENS name and caller address (which is the relayer in the API flow). Returns an AgentRegistered event with the ID.

bash
// Agent Registry: registerAgent(string _ensName)
// _ensName = "trader-bot.myname.eth"
// Returns: uint256 agentId (via event)
2esetText (ENSIP-25 Attestation)

Sets an ENS text record using the ENSIP-25 agent registration key format. The key encodes the registry address and agent ID so any verifier can cross-check the on-chain Agent struct. This is the cryptographic proof that links the ENS name to the agent registration.

bash
// Public Resolver: setText(node, key, value)
// node  = namehash("trader-bot.myname.eth")
// key   = "agent-registration[0x67D2...0AC8][1]"
// value = "true"
i
The order matters because each step depends on the previous one. You must own the subnode before setting its resolver, and the resolver must be set before you can write records. The agent ID from step 2d is needed for the ENSIP-25 key in step 2e.