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/reverseBase 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
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:
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).
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:
On-chain reverse lookup with the supplied
coinType(or the coinType derived from the interop suffix).On-chain reverse lookup with the ENSIP-19 default coinType (
0x80000000) — covers L2 names with a chain-agnostic reverse record.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: nullis 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: nullwith a populatederror, and the rest of the batch succeeds.For batch slots that fail preflight (malformed interop suffix, unsupported chain label, missing
coinTypefor a plain address),coinTypeisnull.
Labelling a multi-chain list
Errors
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:
x402 v2 — Coinbase's HTTP-payment protocol. See x402.org.
MPP-charge — IETF Internet-Draft
draft-httpauth-payment-00with EVM methoddraft-evm-charge-00. Co-authored by Tempo Labs and Stripe.
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:
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 randomnonce.validBeforeshould be ~10 min fromnow(). 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
402with 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 carriesx-payment-info: { offers: [{ amount, currency, description, intent, method }] }perdraft-payment-discovery-00.
Payment-path errors
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