Public API for querying ENS domain data. All endpoints return JSON.
Pass your key via the X-API-Key header. Sign up to get a key with 1,000 free credits.
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.
/api endpoints. You can call these from any origin.Look up a domain.
Returns domain data with ownership, expiry, resolver, wrapped status, and availability information.
| Name | Type | Description |
|---|---|---|
| name | string | Full ENS name (e.g. vitalik.eth) |
{
"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"
}
| Name | Type | Description |
|---|---|---|
| names | string[] | Array of full ENS names (e.g. ["vitalik.eth", "nick.eth"]). Optional if namehashes is provided. |
| namehashes | string[] | 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"]
}
{
"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
}
}
Search domains with filters.
| Name | Type | Description |
|---|---|---|
| q | string | Search query (matches label by default) |
| search_full_name | string | Set to true to search full_name instead of label |
| availability_status | string | Filter: registered, grace, premium, available |
| min_length | integer | Minimum label length |
| max_length | integer | Maximum label length |
| registrar_owner | string | Filter by registrar owner address (exact, case-insensitive) |
| wrapper_owner | string | Filter by wrapper owner address (exact, case-insensitive) |
| registry_owner | string | Filter by registry owner address (exact, case-insensitive) |
| resolver | string | Filter by resolver address (exact, case-insensitive) |
| expiry_from | integer | Minimum expiry (unix timestamp) |
| expiry_to | integer | Maximum expiry (unix timestamp) |
| is_wrapped | string | true or false |
| sort_by | string | full_name (default), label, expiry_timestamp, effective_owner_address |
{
"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
}
Get all on-chain events for a domain. Only non-null fields are included in each event object. A paid renewal through a v1 controller also has duration (seconds) and cost_usd, its exact price in USD; cost is as logged, which for the 2023 controller (CONTROLLER_16925617) is the amount sent, of which all but the price was refunded.
| Name | Type | Description |
|---|---|---|
| name | string | Full ENS name (e.g. vitalik.eth) |
{
"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..."
}
]
}
List direct subdomains of a domain.
| Name | Type | Description |
|---|---|---|
| name | string | Parent domain name (e.g. vitalik.eth) |
| Name | Type | Description |
|---|---|---|
| sort_by | string | full_name (default) |
{
"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
}
Registration and renewal history for a domain. Each entry has registry: ensv1, paid in ETH (cost_wei, cost_eth; a paid renewal also has cost_usd, its exact price in USD, payment_symbol: "ETH" and duration in seconds, and a renewal through the 2023 controller, which logs the amount sent rather than the price, has cost_eth null and sent_wei, sent_eth instead), or ensv2, paid in a stablecoin through the ENSv2 registrar (payment_token, payment_symbol, cost_amount in the token's units, cost_usd, duration in seconds, referrer; cost_wei and cost_eth are null).
| Name | Type | Description |
|---|---|---|
| name | string | Full ENS name (e.g. vitalik.eth) |
| merged | string | true (default) merges events from the same transaction; false returns individual events with a contract field |
{
"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": []
}
Returns current resolver records for a domain: text records, multi-chain addresses, and contenthash.
| Name | Type | Description |
|---|---|---|
| name | string | Full ENS name (e.g. vitalik.eth) |
| Name | Type | Description |
|---|---|---|
| types | string | Comma-separated: text, addr, contenthash (default: all) |
{
"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"
}
Look up a single text record for a domain.
| Name | Type | Description |
|---|---|---|
| name | string | Full ENS name (e.g. vitalik.eth) |
| key | string | Text record key (e.g. com.x, avatar) |
{
"domain": "vitalik.eth",
"resolver": {
"status": "indexed",
"chain": "mainnet",
"address": "0x231b0ee1..."
},
"key": "com.x",
"value": "VitalikButerin",
"block_number": 18500000,
"transaction_hash": "0xabc...",
"source": "indexed"
}
Effective ownership history for a domain, derived from on-chain events.
Returns ownership periods with the resolved effective owner at each point in time. reason says which owner it is: ensv2 (the ENSv2 token holder, which outranks v1 once a name is on ENSv2), wrapped, registrar or registry.
| Name | Type | Description |
|---|---|---|
| name | string | Full ENS name (e.g. vitalik.eth) |
| audit | string | true to include per-contract breakdown (registry, registrar, wrapper, ensv2 arrays). Default false |
{
"history": [
{
"address": "0xd8dA6BF2...",
"reason": "registrar",
"from_block": 9500000,
"from_tx": "0xdef456...",
"to_block": null,
"to_tx": null
}
]
}
Resolver change history derived from stored on-chain events. Each entry represents a period where a specific resolver contract was active for the domain, with registry ensv1 or ensv2. Once a name is registered on ENSv2 (migrated or registered again), its resolver changes come from ENSv2, and later v1 resolver changes are ignored. Block numbers are numbers.
| Name | Type | Description |
|---|---|---|
| name | string | Full ENS name (e.g. vitalik.eth) |
{
"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
}
]
}
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.
| Name | Type | Description |
|---|---|---|
| name | string | Full ENS name (e.g. vitalik.eth) |
| key | string | Text record key (e.g. avatar, com.twitter) |
{
"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 eventresolver_change - the resolver changed, invalidating the previous valuelive - current value from live on-chain resolutionLook up a domain by any hash. Tries namehash first (unique match), then falls back to labelhash (may match multiple domains).
| Name | Type | Description |
|---|---|---|
| hash | string | A 66-character hex string (0x + 64 hex chars) |
{
"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..."
}
}
{
"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..."
}
}
]
}
{
"hash": "0xee6c4522...",
"indexed": false
}
Look up a single domain by its namehash. Returns full domain details including ownership, resolver, and wrapped status.
| Name | Type | Description |
|---|---|---|
| hash | string | Namehash - a 66-character hex string (0x + 64 hex chars) |
{
"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..."
}
}
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).
| Name | Type | Description |
|---|---|---|
| hash | string | Labelhash - a 66-character hex string (0x + 64 hex chars) |
{
"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
}
A .eth second-level name's position on ENSv2, read live from mainnet (cached for 2 minutes): its reservation on the v2 .eth registry and whether that is in sync with v1, when it stops resolving and when it is released, what a renewal costs and where, and how it would migrate.
Every active or in-grace v1 name is reserved on v2 with an expiry of its v1 expiry plus 62 days, and ENS Labs' daily pre-migration sync (BatchRegistrar) keeps the two in step. ENSv2 then gives 28 days of grace, so the name is released at v1 expiry plus 90 days, the same day as on v1. A name in v2 grace doesn't resolve: since the resolution cutover (27 October 2026) names resolve through ENSv2 only.
Subnames and DNS names return applicable: false.
| Name | Type | Description |
|---|---|---|
| name | string | A .eth 2LD, e.g. nick.eth |
| Field | Description |
|---|---|
| state | reserved, reserved_pending_sync (v1 renewed, not yet synced), not_resolving (v2 reservation lapsed, v1 still in grace), not_reserved, migrated, released, unregistered |
| v1 / v2 | Expiries (unix seconds and ISO), v1 state, v2 status, in_sync, resolves, and the v2 owner once migrated |
| released_at | When the name becomes registrable by anyone if not renewed |
| notice | A warning or note for the holder, or null |
| renewal | 1-year price on ENSv2 (one_year_usd), on v1 while it is still the way to renew (v1_one_year_usd), and via: ens_v1, eth_renewer_v1 or ens_v2_registrar |
| migration | Path (unwrapped, wrapped_unlocked, wrapped_locked), controller, ready, blockers, and the v2 permissions the name would get |
| rollout | Live flags: v1_frozen, registrations_open, migration_open |
{
"name": "jefflau.eth",
"applicable": true,
"state": "reserved",
"v1": { "expiry": 1935676872, "grace_ends": 1943452872, "state": "active" },
"v2": { "status": "reserved", "expiry": 1941033672, "in_sync": true, "resolves": true, "owner": null },
"released_at": 1943452872,
"notice": null,
"renewal": { "one_year_usd": 8.00002, "v1_one_year_usd": 5, "length": 7, "via": "ens_v1" },
"migration": {
"path": "wrapped_unlocked",
"ready": false,
"blockers": [{ "code": "migration_not_open", "message": "..." }],
"token_roles": ["SET_SUBREGISTRY", "SET_SUBREGISTRY (admin)", "SET_RESOLVER", "SET_RESOLVER (admin)", "CAN_TRANSFER (admin)"]
},
"rollout": { "v1_frozen": false, "registrations_open": false, "migration_open": false }
}
Price by term for any name: enswhois.com/ensv2/pricing.
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.
| Name | Type | Description |
|---|---|---|
| name | string | Full ENS name (e.g. enswhois.eth) |
| Field | Type | Description |
|---|---|---|
| profile | object | The agent's ENSIP-26 records: context (agent-context) and endpoints.mcp/a2a/web. Self-asserted - treat as untrusted. |
| registrations[] | array | An array (for forward-compatability) of agent registration data. |
{
"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..."
}
}
]
}
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.
| Name | Type | Description |
|---|---|---|
| page | integer | Page number (25 per page) |
| q | string | Filter by name substring |
| sort | string | registered (default) or name |
| dir | string | asc or desc |
| has | string | Comma-separated filters: mcp, a2a, web, context (record presence), and ensip25 (has a valid conformant ENSIP-25 registration) |
{
"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
}
profile data safely, and the three integration patterns.