ENS Indexer API

API Documentation

ENSWhois Docs Agents Status API

Public API for querying ENS domain data. All endpoints return JSON.

https://api.enswhois.com

Authentication

API Key

Pass your key via the X-API-Key header. Sign up to get a key with 1,000 free credits.

Micropayments (MPP)

Pay per request using the MPP protocol. No account needed — pay directly from your wallet.

No authentication is needed to try the API - unauthenticated requests are limited to 5 per minute. Sign up for unlimited access.

CORS is enabled for all /api endpoints. You can call these from any origin.

Lookup

GET /whois/:name

Look up a domain.

Returns domain data with ownership, expiry, resolver, wrapped status, and availability information.

Parameters

NameTypeDescription
namestringFull ENS name (e.g. vitalik.eth)

Example Response

{
  "name": "vitalik.eth",
  "display": "Vitalik.eth",
  "label": "vitalik",
  "labelhash": "0xaf2caa1c...",
  "token_id": "7960091...",
  "namehash": "0xee6c4522...",
  "parent_node": "0x93cdeb7...",
  "parent_name": "eth",
  "expiry_timestamp": "1754000000",
  "ownership": {
    "is_wrapped": false,
    "owner": "0xd8dA6BF2...",
    "registry": "0xd8dA6BF2...",
    "registrar": "0xd8dA6BF2..."
  },
  "resolver": {
    "status": "indexed",
    "chain": "mainnet",
    "address": "0x231b0ee1..."
  },
  "availability_status": "registered",
  "query": "vitalik.eth",
  "source": "indexed"
}
POST /whois/bulk
  • Bulk lookup for multiple domains by name or namehash
  • Maximum 500 items per request (names + namehashes combined)
  • Each result uses the same fields as the single whois endpoint

Request Body

NameTypeDescription
namesstring[]Array of full ENS names (e.g. ["vitalik.eth", "nick.eth"]). Optional if namehashes is provided.
namehashesstring[]Array of namehash hex strings (0x + 64 hex chars). Optional if names is provided.

At least one of names or namehashes must be provided. Both can be used together in a single request.

{
  "names": ["vitalik.eth", "nick.eth"],
  "namehashes": ["0xee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835"]
}

Example Response

{
  "results": [
    {
      "query": "vitalik.eth",
      "name": "vitalik.eth",
      "display": "Vitalik.eth",
      "label": "vitalik",
      "expiry_timestamp": "1754000000",
      "ownership": { "..." },
      "resolver": { "..." },
      "availability_status": "registered",
      "source": "indexed"
    },
    {
      "query": "nonexistent.eth",
      "availability_status": "available",
      "source": "indexed"
    }
  ],
  "summary": {
    "total": 2,
    "registered": 1,
    "grace": 0,
    "premium": 0,
    "available": 1,
    "unknown": 0,
    "expiring_30d": 0
  }
}
GET /search-domains Paginated

Search domains with filters.

Query Parameters

NameTypeDescription
qstringSearch query (matches label by default)
search_full_namestringSet to true to search full_name instead of label
availability_statusstringFilter: registered, grace, premium, available
min_lengthintegerMinimum label length
max_lengthintegerMaximum label length
registrar_ownerstringFilter by registrar owner address (exact, case-insensitive)
wrapper_ownerstringFilter by wrapper owner address (exact, case-insensitive)
registry_ownerstringFilter by registry owner address (exact, case-insensitive)
resolverstringFilter by resolver address (exact, case-insensitive)
expiry_fromintegerMinimum expiry (unix timestamp)
expiry_tointegerMaximum expiry (unix timestamp)
is_wrappedstringtrue or false
sort_bystringfull_name (default), label, expiry_timestamp, effective_owner_address

Example Response

{
  "results": [
    {
      "name": "vitalik.eth",
      "display": "Vitalik.eth",
      "label": "vitalik",
      "expiry_timestamp": "1754000000",
      "ownership": {
        "owner": "0xd8dA6BF2...",
        "is_wrapped": false
      }
    }
  ],
  "stats": {
    "expired": 12,
    "expiring_30d": 3,
    "expiring_90d": 8,
    "wrapped": 210,
    "wrapped_pct": 39.5
  },
  "total": 532,
  "page": 1,
  "page_size": 25
}

Events & Sub-Resources

GET /domain/:name/events

Get all on-chain events for a domain. Only non-null fields are included in each event object.

Parameters

NameTypeDescription
namestringFull ENS name (e.g. vitalik.eth)

Example Response

{
  "events": [
    {
      "contract": "CONTROLLER_9380470",
      "event_type": "NameRegistered",
      "block_number": 9380471,
      "transaction_hash": "0xabc...",
      "owner_address": "0xd8dA6BF2...",
      "cost_wei": "3200000000000000",
      "expiry_timestamp": "1754000000"
    },
    {
      "contract": "REGISTRY",
      "event_type": "NewOwner",
      "block_number": 9380471,
      "transaction_hash": "0xabc...",
      "owner_address": "0xd8dA6BF2..."
    }
  ]
}
GET /domain/:name/subdomains Paginated

List direct subdomains of a domain.

Only returns subnames created via on-chain events. Off-chain subnames (e.g. ENSIP-10 wildcard or CCIP-Read) are not discoverable by the indexer.

Parameters

NameTypeDescription
namestringParent domain name (e.g. vitalik.eth)

Query Parameters

NameTypeDescription
sort_bystringfull_name (default)

Example Response

{
  "domain": "vitalik.eth",
  "results": [
    {
      "name": "sub.vitalik.eth",
      "label": "sub",
      "expiry_timestamp": null,
      "ownership": {
        "owner": "0xd8dA6BF2...",
        "is_wrapped": false
      },
      "resolver": {
        "address": "0x231b0Ee1..."
      }
    }
  ],
  "total": 3,
  "page": 1,
  "page_size": 25
}
GET /domain/:name/registration-history

Registration and renewal history for a domain.

Parameters

NameTypeDescription
namestringFull ENS name (e.g. vitalik.eth)
mergedstringtrue (default) merges events from the same transaction; false returns individual events with a contract field

Example Response

{
  "domain": "vitalik.eth",
  "registrations": [
    {
      "event_type": "NameRegistered",
      "block_number": 9380471,
      "transaction_hash": "0xabc...",
      "cost_wei": "3200000000000000",
      "cost_eth": "0.003200",
      "expiry_timestamp": "1754000000",
      "owner_address": "0xd8dA..."
    }
  ],
  "renewals": []
}
GET /domain/:name/records

Returns current resolver records for a domain: text records, multi-chain addresses, and contenthash.

Parameters

NameTypeDescription
namestringFull ENS name (e.g. vitalik.eth)

Query Parameters

NameTypeDescription
typesstringComma-separated: text, addr, contenthash (default: all)

Example Response

{
  "domain": "vitalik.eth",
  "resolver": {
    "status": "indexed",
    "chain": "mainnet",
    "address": "0x231b0ee1..."
  },
  "records": {
    "texts": {
      "com.twitter": "VitalikButerin",
      "avatar": "eip155:1/..."
    },
    "addresses": {
      "60": "0xd8dA6BF2..."
    },
    "contenthash": null
  },
  "source": "indexed"
}
GET /domain/:name/records/text/:key

Look up a single text record for a domain.

Parameters

NameTypeDescription
namestringFull ENS name (e.g. vitalik.eth)
keystringText record key (e.g. com.x, avatar)

Example Response

{
  "domain": "vitalik.eth",
  "resolver": {
    "status": "indexed",
    "chain": "mainnet",
    "address": "0x231b0ee1..."
  },
  "key": "com.x",
  "value": "VitalikButerin",
  "block_number": 18500000,
  "transaction_hash": "0xabc...",
  "source": "indexed"
}

Derived History

GET /domain/:name/ownership-history

Effective ownership history for a domain, derived from on-chain events.

Returns ownership periods with the resolved effective owner at each point in time.

Parameters

NameTypeDescription
namestringFull ENS name (e.g. vitalik.eth)
auditstringtrue to include per-contract breakdown (registry, registrar, wrapper arrays). Default false

Example Response

{
  "history": [
    {
      "address": "0xd8dA6BF2...",
      "reason": "registrar",
      "from_block": 9500000,
      "from_tx": "0xdef456...",
      "to_block": null,
      "to_tx": null
    }
  ]
}
GET /domain/:name/resolver-history

Resolver change history derived from stored on-chain events. Each entry represents a period where a specific resolver contract was active for the domain.

Parameters

NameTypeDescription
namestringFull ENS name (e.g. vitalik.eth)

Example Response

{
  "history": [
    {
      "address": "0x4976fb03...",
      "from_block": 9412610,
      "from_tx": "0xdef456...",
      "to_block": 16773775,
      "to_tx": "0x789abc..."
    },
    {
      "address": "0x231b0Ee1...",
      "from_block": 16773775,
      "from_tx": "0x789abc...",
      "to_block": null,
      "to_tx": null
    }
  ]
}
GET /domain/:name/records/text/:key/history

Change history for a specific text record. Only includes changes from the domain's active resolver at the time - records set on non-active resolvers are excluded. Resolver changes are included as null-value boundaries.

Parameters

NameTypeDescription
namestringFull ENS name (e.g. vitalik.eth)
keystringText record key (e.g. avatar, com.twitter)

Example Response

{
  "domain": "vitalik.eth",
  "key": "avatar",
  "history": [
    {
      "value": "eip155:1/...",
      "block_number": 18500000,
      "resolver": "0x231b0ee1...",
      "source": "indexed",
      "transaction_hash": "0xabc..."
    },
    {
      "value": null,
      "block_number": 16773775,
      "source": "resolver_change"
    },
    {
      "value": "old-avatar",
      "block_number": 15000000,
      "resolver": "0x4976fb03...",
      "source": "indexed",
      "transaction_hash": "0xdef..."
    }
  ]
}

Each entry's source indicates provenance:

  • indexed - from an on-chain TextChanged event
  • resolver_change - the resolver changed, invalidating the previous value
  • live - current value from live on-chain resolution

Hash Lookups

GET /lookup-hash/:hash

Look up a domain by any hash. Tries namehash first (unique match), then falls back to labelhash (may match multiple domains).

Parameters

NameTypeDescription
hashstringA 66-character hex string (0x + 64 hex chars)

Example Response (namehash match)

{
  "type": "namehash",
  "name": "vitalik.eth",
  "display": "Vitalik.eth",
  "label": "vitalik",
  "token_id": "7960091...",
  "namehash": "0xee6c4522...",
  "labelhash": "0xaf2caa1c...",
  "parent_name": "eth",
  "parent_node": "0x93cdeb7...",
  "expiry_timestamp": "1754000000",
  "ownership": {
    "owner": "0xd8dA6BF2...",
    "is_wrapped": false
  },
  "resolver": {
    "status": "indexed",
    "chain": "mainnet",
    "address": "0x231b0ee1..."
  }
}

Example Response (labelhash match)

{
  "type": "labelhash",
  "domains": [
    {
      "name": "vitalik.eth",
      "display": "Vitalik.eth",
      "label": "vitalik",
      "token_id": "7960091...",
      "namehash": "0xee6c4522...",
      "labelhash": "0xaf2caa1c...",
      "parent_name": "eth",
      "parent_node": "0x93cdeb7...",
      "expiry_timestamp": "1754000000",
      "ownership": {
        "owner": "0xd8dA6BF2...",
        "is_wrapped": false
      },
      "resolver": {
        "status": "indexed",
        "chain": "mainnet",
        "address": "0x231b0ee1..."
      }
    }
  ]
}

Example Response (not indexed)

{
  "hash": "0xee6c4522...",
  "indexed": false
}
GET /lookup-namehash/:hash

Look up a single domain by its namehash. Returns full domain details including ownership, resolver, and wrapped status.

Parameters

NameTypeDescription
hashstringNamehash - a 66-character hex string (0x + 64 hex chars)

Example Response

{
  "name": "vitalik.eth",
  "display": "Vitalik.eth",
  "label": "vitalik",
  "token_id": "7960091...",
  "namehash": "0xee6c4522...",
  "labelhash": "0xaf2caa1c...",
  "parent_name": "eth",
  "parent_node": "0x93cdeb7...",
  "expiry_timestamp": "1754000000",
  "ownership": {
    "owner": "0xd8dA6BF2...",
    "registry": "0xd8dA6BF2...",
    "registrar": "0xd8dA6BF2...",
    "is_wrapped": false
  },
  "resolver": {
    "status": "indexed",
    "chain": "mainnet",
    "address": "0x231b0ee1..."
  }
}
GET /lookup-labelhash/:hash Paginated

Look up domains by labelhash. A labelhash can match multiple domains across different parent names (e.g. vitalik.eth and vitalik.xyz share the same labelhash).

Parameters

NameTypeDescription
hashstringLabelhash - a 66-character hex string (0x + 64 hex chars)

Example Response

{
  "domains": [
    {
      "name": "vitalik.eth",
      "display": "Vitalik.eth",
      "label": "vitalik",
      "token_id": "7960091...",
      "namehash": "0xee6c4522...",
      "labelhash": "0xaf2caa1c...",
      "parent_name": "eth",
      "parent_node": "0x93cdeb7...",
      "expiry_timestamp": "1754000000",
      "ownership": {
        "owner": "0xd8dA6BF2...",
        "is_wrapped": false
      },
      "resolver": {
        "status": "indexed",
        "chain": "mainnet",
        "address": "0x231b0ee1..."
      }
    }
  ],
  "total": 1,
  "page": 1,
  "page_size": 25
}

ERC-8004 Agents

GET /domain/:name/agent

Is this ENS name an ERC-8004 agent?

We consider a name an agent when it has an on-chain binding in the Adapter8004 adapter.

The Integrating ENS Agents guide covers the trust model and how to render the profile safely.

Parameters

NameTypeDescription
namestringFull ENS name (e.g. enswhois.eth)

Response Fields

FieldTypeDescription
profileobjectThe agent's ENSIP-26 records: context (agent-context) and endpoints.mcp/a2a/web. Self-asserted - treat as untrusted.
registrations[]arrayAn array (for forward-compatability) of agent registration data.

Example Response

{
  "name": "enswhois.eth",
  "display": "ENSWhois.eth",
  "namehash": "0x75aca3b6...",
  "owner": "0xac50ce32...",
  "is_wrapped": false,
  "expiry_timestamp": 1812548051,
  "is_expired": false,
  "avatar": "https://...",
  "profile": {
    "context": "Agentic interface to ENSWhois.com...",
    "endpoints": {
      "mcp": "https://mcp.enswhois.com/mcp",
      "a2a": null,
      "web": "https://enswhois.com/"
    }
  },
  "registrations": [
    {
      "registry": {
        "caip10": "eip155:1:0x8004A169FB4a3325136EB29fA0ceB6D2e539a432",
        "erc7930": "0x000100000101148004a169fb4a3325136eb29fa0ceb6d2e539a432"
      },
      "agent_id": "34339",
      "has_ensip25_registration": true,
      "is_bound": true,
      "binding": {
        "adapter": "0xde152afb7db5373f34876e1499fbd893a82dd336",
        "token_standard": 0,
        "token_contract": "0x57f1887a8bf19b14fc0df6fd9b2acc9af147ea85",
        "token_id": "1073289...",
        "token_uri": "https://...",
        "agent_owner": "0xac50ce32...",
        "registered_block": 25280217,
        "registered_at": "2026-06-09T13:37:59.000Z",
        "registered_by": "0xac50ce32..."
      }
    }
  ]
}
GET /agents Paginated

This endpoint returns all ENS agents. We consider a name an agent when it has an on-chain binding in the Adapter8004 adapter.

The Integrating ENS Agents guide covers the trust model and how to render the profile safely.

Query Parameters

NameTypeDescription
pageintegerPage number (25 per page)
qstringFilter by name substring
sortstringregistered (default) or name
dirstringasc or desc
hasstringComma-separated filters: mcp, a2a, web, context (record presence), and ensip25 (has a valid conformant ENSIP-25 registration)

Example Response

{
  "agents": [
    {
      "name": "enswhois.eth",
      "display": "ENSWhois.eth",
      "namehash": "0x75aca3b6...",
      "owner": "0xac50ce32...",
      "is_wrapped": false,
      "expiry_timestamp": 1812548051,
      "is_expired": false,
      "avatar": "https://...",
      "profile": {
        "context": "Agentic interface to ENSWhois.com...",
        "endpoints": { "mcp": "https://...", "a2a": null, "web": "https://..." }
      },
      "registrations": [
        {
          "registry": {
            "caip10": "eip155:1:0x8004A169FB4a3325136EB29fA0ceB6D2e539a432",
            "erc7930": "0x000100000101148004a169fb4a3325136eb29fa0ceb6d2e539a432"
          },
          "agent_id": "34339",
          "has_ensip25_registration": true,
          "is_bound": true,
          "binding": {
            "adapter": "0xde152afb...",
            "token_standard": 0,
            "token_contract": "0x57f1887a...",
            "token_id": "1073289...",
            "token_uri": null,
            "agent_owner": null,
            "registered_block": 25280217,
            "registered_at": "2026-06-09T13:37:59.000Z",
            "registered_by": "0xac50ce32..."
          }
        }
      ]
    }
  ],
  "total": 49,
  "page": 1,
  "page_size": 25
}
Building an integration? The Integrating ENS Agents guide covers the trust model (what an on-chain binding does and doesn't prove), how to render profile data safely, and the three integration patterns.