Reverse Resolution

Resolve an address into its ENS reverse record on a given chain. Given 0xd8dA6BF…, returns vitalik.eth so you can show a name instead of a hex string. For the opposite direction (name → address and records), see Forward Resolution.

Endpoint

GET /ens/v2/reverse

Base URL: https://api.justaname.id

Quick start

The endpoint is free when you supply your own RPC URL via the rpcUrl query parameter. No API key required. Rate-limited to 30 requests per 60 seconds per IP.

curl "https://api.justaname.id/ens/v2/reverse?address=0xd8da6bf26964af9d7eed9e03e53415d37aa96045&coinType=60&rpcUrl=https://eth.drpc.org"
const url = new URL('https://api.justaname.id/ens/v2/reverse');
url.searchParams.append('address', '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045');
url.searchParams.set('coinType', '60');
url.searchParams.set('rpcUrl', process.env.RPC_URL!);

const res = await fetch(url);

The caller's RPC pays for the on-chain reads. JustaName performs the reverse lookup through the ENS Universal Resolver and falls back to its off-chain reverse-record store when no on-chain reverse record is set.

Autonomous clients without an RPC URL (AI agents, MCP servers, scripts) can pay per-request in USDC on Base instead of supplying rpcUrl. See Programmatic access without an RPC URL.

Parameters

Parameter
Type
Required
Description

address

string (repeatable)

Yes

Address to reverse-resolve. Repeat to batch up to 50 addresses (?address=0x…&address=0x…). Plain (0x…) or interop-formatted — see Interop addresses.

coinType

number

Conditional

ENSIP-19 coinType — see coinType reference. Required for plain addresses; optional when every address in the batch carries an interop suffix.

rpcUrl

string

See below

HTTPS RPC URL used to perform the on-chain resolution.

Either rpcUrl must be present or the request must carry a valid payment header. Without either, the endpoint returns 402 with a payment challenge — see Programmatic access without an RPC URL.

Interop addresses

By default, the request-level coinType applies to every address in the batch. To override per-slot — for example, when batching addresses across different chains — append a chain suffix to the address:

Format
Effect

0xd8dA…6045 (with coinType=60)

Reverse on Ethereum

0xd8dA…6045@ethereum

Reverse on Ethereum (overrides coinType)

0xd8dA…6045@eip155:1

Reverse on Ethereum (overrides coinType)

0xbbb…@eip155:8453

Reverse on Base

Both the human-readable chain name and the CAIP-2 form (eip155:<chainId>) are accepted. The suffix is per-address, so a batch can mix suffixed and request-level-scoped slots:

When every address in the batch carries a suffix, the request-level coinType becomes optional.

RPC URL requirements

Same as Forward Resolution: HTTPS only, no private/loopback/link-local hosts, no embedded credentials.

coinType reference

ENSIP-19 coinTypes follow the formula 0x80000000 | chainId for EVM L2 primaries. Ethereum mainnet is the exception (60).

Chain
Decimal
Hex

Ethereum mainnet

60

0x3c

Optimism

2147483658

0x8000000a

Base

2147492837

0x80002105

Arbitrum One

2147525809

0x8000a4b1

ENSIP-19 default (step-2 fallback)

2147483648

0x80000000

Response

Returns a single object when one address is requested, or an array of slot-level objects (with per-slot error) when multiple are requested.

Single address

Batch

Behavior

For each address, a 3-step fallback chain is walked. The first hit wins:

  1. On-chain reverse lookup with the supplied coinType (or the coinType derived from the interop suffix).

  2. On-chain reverse lookup with the ENSIP-19 default coinType (0x80000000) — covers L2 names with a chain-agnostic reverse record.

  3. JustaName off-chain reverse-record store.

Other notes:

  • viaUniversalResolver: true → resolved on-chain (step 1 or 2). viaUniversalResolver: false → resolved from the JustaName off-chain store (step 3).

  • name: null is a normal outcome (most addresses do not have a reverse record set), not a failure.

  • In batch mode, slot failures are localized: the slot returns name: null with a populated error, and the rest of the batch succeeds.

  • For batch slots that fail preflight (malformed interop suffix, unsupported chain label, missing coinType for a plain address), coinType is null.

Labelling a multi-chain list

Errors

Status
When

400

rpcUrl not HTTPS, has embedded credentials, or resolves to a private/loopback host.

400

address malformed (not 0x[40-hex] optionally followed by @<chain>).

400

address array empty or > 50 entries.

400

Single-address request with a plain address and no coinType.

400

Unknown chain label in the interop suffix.

429

Rate limit (30 req / 60 s per IP) exceeded. Body includes retryAfterSeconds.

502 / 504

RPC provider error or CCIP-Read gateway timeout.

Payment-related statuses (402, 503) are documented in the paid path section.


Programmatic access without an RPC URL

For clients that don't manage their own RPC infrastructure — AI agents, MCP servers, autonomous scripts — the endpoint accepts per-request payment in place of rpcUrl. The service performs the on-chain reads and charges the caller in USDC on Base.

Two protocols are accepted on the same route. Clients pick whichever fits their stack:

Both protocols settle identically — a signed EIP-3009 transferWithAuthorization submitted by a facilitator on Base. They differ only in HTTP envelope.

Chain

Base mainnet (eip155:8453)

Asset

USDC (0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913)

Price

1000 base units per request (0.001 USDC at 6 decimals)

402 challenge

A request without rpcUrl and without a payment header receives both challenges in one response. The headers are disjoint, so they coexist:

Decoded PAYMENT-REQUIRED (x402 v2):

Decoded WWW-Authenticate request= (MPP draft-evm-charge-00):

Paying

Sign an EIP-3009 transferWithAuthorization against the USDC contract on Base (e.g. viem's signTypedData with primaryType: "TransferWithAuthorization" and a fresh 32-byte nonce). Wrap the signed message in either envelope and retry the request:

Scheme
Request header
Receipt header (on 200)

x402 v2

PAYMENT-SIGNATURE: <base64 JSON>

PAYMENT-RESPONSE: <base64 JSON>

MPP-charge

Authorization: Payment <base64url-nopad JSON>

Payment-Receipt: <base64url-nopad JSON>

The facilitator submits the on-chain tx and pays gas — the payer only needs USDC, not ETH.

Idempotency, replay, validity

  • Set Idempotency-Key: <uuid> on every retry. Without it, each retry is a fresh payment.

  • (nonce, recipient) is locked in a 5-minute LRU. Always sign with a fresh random nonce.

  • validBefore should be ~10 min from now(). Longer windows risk re-sending stale signatures past expiry.

  • A retriable failure (facilitator transient error) returns 503 + Retry-After. Repeat the same request.

  • A non-retriable failure (malformed payload, replay, network/asset mismatch) returns a fresh 402 with the reason in the challenge.

Discovery

  • GET /ens/v2/pricing (free) — JSON list of paid routes: { path, method, schemes, amount, asset, network, recipient }.

  • GET /.well-known/x402.json (free) — x402 manifest (services[] + accepts[]) for catalog crawlers (Bazaar, x402scan).

  • GET /openapi.json — OpenAPI document. Each paid operation carries x-payment-info: { offers: [{ amount, currency, description, intent, method }] } per draft-payment-discovery-00.

Payment-path errors

Status
When

402

Request lacks rpcUrl and no payment header was supplied. PAYMENT-REQUIRED and WWW-Authenticate carry the challenge.

402

Payment proof was malformed, replayed, expired, or targeted the wrong network/asset.

503

Facilitator transient error during verify/settle. Retry-After set; repeat the same request.

Last updated