Names
An address can carry several names (a preferred .chain name, a middleware-resolved chain
name, an X handle), and the Superhero API resolves one of them into a public_name for
display. The name types differ in how much evidence backs them, so know which one you are
looking at before you cache it.
Name types
| Type | Where it lives | How it gets there | Verified? |
|---|---|---|---|
| Preferred AENS name | AddressLink, provider prefaens | link_principal, which calls AENSv2.lookup inside the contract | Yes: ownership is checked on chain |
| Chain name | chain_name on the account | Resolved from the middleware, refreshed on an hourly sweep and on a stale read | Yes, by resolution rather than by claim |
| X handle | AddressLink, provider x | link after an OAuth check the backend performs | Off chain only; see X verification |
| Legacy username | profile.username | Read-only legacy field | No |
How a public name is resolved
The API walks four steps and returns the first non-empty value:
prefered_aens_name (links.prefaens — the AENS name you explicitly linked)
chain_name (resolved from the middleware)
username (the legacy profile field)
address (the ak_… itself)A linked preferred name overrides the middleware-resolved one on purpose: an address can own several AENS names, and the middleware returns the first. Linking one says which.
The resolved value is public_name on GET /api/profile/{address} and
GET /api/accounts/{address}. There is no per-account preference that changes the order.
How the chain name stays fresh
chain_name is cached with a chain_name_updated_at timestamp. An hourly sweep refreshes it,
and GET /api/accounts/{address} also refreshes on read when the cached value is older
than the staleness window, writing the new value back asynchronously. An expired or transferred
AENS name therefore drops out of the profile within about an hour.
chain_expires_at in the profile aggregate is a legacy field and is not refreshed. To check
whether a name is live, resolve it through AENS.
Reverse resolution
AddressLink provides two reverse lookups, both free dry-run reads backed by the contract's
reverse map:
| Call | Answers |
|---|---|
resolve(provider, value) | Which address holds this provider value, for example which address linked the X handle superherocom |
resolve_signer(principal) | Which address linked this AENS name as a principal |
What the app displays
The profile header takes the first non-empty value of:
links.prefered_aens_name (the preferred AENS name from the account aggregate)
public_name (the name the API resolved, by the ladder above)
chainName (the AENS name looked up for the address)
formatAddress(address) (a shortened ak_… fallback)A verified badge is rendered when an x link exists for the account. See
Verifying Your X Account for what that link proves.
Normalization
| Layer | Rule |
|---|---|
| Client | normalizeName(value) = value.trim().toLowerCase(); normalizeChainNameLabel additionally strips a trailing .chain |
| Backend, on read | links.x is trimmed, lowercased and has a leading @ stripped; links.bio, links.site and links.prefaens are trimmed only |
| Backend, on write | The value must be at most 200 characters and must not contain a :, because the signed message is colon-delimited |
The site provider also strips the scheme (https://example.com/blog is stored as
example.com/blog) and rejects a port.
The contract stores the value string verbatim, so whatever the backend normalized is what is on chain.
Worked examples
Link a .chain name. Claim the AENS name first, because the identity layer does not claim it for
you. Then run the claim-sign-submit flow at /api/address-links/prefered-aens-name/. The
signed message puts the name in the subject slot rather than your address:
link:hero.chain:prefaens:hero.chain:0The backend calls link_principal, and the contract verifies with AENSv2.lookup that you own
the name. PRINCIPAL_NOT_FOUND means the name is not registered; PRINCIPAL_MISMATCH means
you do not own it.
Link an X handle. Complete the OAuth leg, sign link:ak_…:x:yourhandle:<nonce>, and
submit with the verification token. The handle is stored lowercased.
Change which name shows. Link a different .chain name, or unlink prefaens to fall back
to the middleware-resolved name.
Remove a name. unclaim then unclaim/submit on the matching provider path. Only your
own signature is required, with no OAuth or AENS check.
Related
- AddressLink: the contract behind every link.
- Chain Names (AENS): how to get the
.chainname that sits at the top of the resolution ladder. - Verifying Your X Account: the
xlink, and what a verified badge means. - Profiles & Accounts: where the resolved name ends up on screen.
- æternity Naming System (AENS) (opens in a new tab): the protocol-level name system a chain name is anchored to.