The did:namid DID method.
Every NamID name is a W3C Decentralized Identifier. This page is the method specification: the identifier syntax, the DID document a name resolves to, the four operations, and the security and privacy considerations. Resolve one now: https://namid.net/api/did/resolve?did=did:namid:testnet11:agentr.x
Status: Draft, 2026-10-20 (v0.1: 2026-09-23) · Owner: Web3UTXO (NamID Protocol)
Method name: namid · Ledger: Chia blockchain (singleton coins) · Licence: CC0
Registry entry: to be submitted to the W3C DID Extensions "DID Methods" registry
(w3c/did-extensions, methods.json) once this document is published at
https://namid.net/did-namid.html.
Reference implementation: did_namid.py and tld_uri.py in
apps/NalandaX/registry-Backend-artefacts/; tests in tests/test_did_namid.py.
Protocol: this method is summarised in whitepaper §3.6;
section numbers written "whitepaper §" below point into the whitepaper (v1.5).
This document follows the requirements for DID method specifications in DID Core §8: method name, method-specific identifier syntax, the four operations, security and privacy considerations.
1. Why a method of its own
NamID is a naming protocol on Chia in which every name is an identity: a root (x,
mojo, nm) and a name beneath it (yourname.x) are each a singleton coin, the name's
deed, which is a standard Chia DID whose id is its launcher id
(whitepaper §3.2). Chia wallets already print DIDs as did:chia:1…, but
did:chia is not a registered DID method and has no method specification; the only
Chia-singleton method in the W3C registry is did:julia. A NamID identifier presented to
the wider DID ecosystem therefore needs a method that is specified, resolvable and
registered. did:namid is that method.
Nothing older changes. The same 32 launcher bytes remain spellable as did:chia:1…
(Chia-ecosystem interop), tld:1… (protocol-internal) and namid:1… (the protocol's own
URI); the did:namid document lists all of them under alsoKnownAs.
2. Method name
The method name is namid. A DID that uses this method MUST begin with did:namid:.
3. Method-specific identifier
did-namid = "did:namid:" [ network ":" ] id
network = 1*16( %x61-7A / DIGIT ) ; lowercase; OMITTED on mainnet
id = launcher-id / name
launcher-id = "1" 1*bech32-char ; bech32m, checksum computed over the hrp "namid:"
name = label *( "." label )
label = ( %x61-7A / DIGIT ) *61( %x61-7A / DIGIT / "-" )
- Launcher form —
did:namid:1<bech32m>(mainnet) ordid:namid:testnet11:1<bech32m>. The bech32m string afterdid:is exactly the protocol URInamid:1…: the human-readable part of the checksum isnamid:, sodid:namid:1…andnamid:1…share one checksum and one 32-byte payload, the launcher id of the name's singleton coin. This form is the canonical DID of a name once its coin exists on chain; it never changes for the life of the coin lineage. - Name form —
did:namid:yourname.x/did:namid:testnet11:yourname.x. A valid DID (DID Core allows.and-in the method-specific id) that resolves to the same document. It is the DID of a name before its coin is minted, and anequivalentIdof the launcher form afterwards. - Network — omitted for the Chia mainnet; any other network names itself
(
testnet11).did:namid:mainnet:…is invalid. A resolver serves one network and answersnotFoundfor another. - Case — a
did:namididentifier is lowercase; uppercase is invalid, not normalised. - Payment addresses are not identifiers — an id matching
^t?xch1[bech32]{20,}$is invalid by grammar, because anxch1…string is a Chia address and an identifier that looks like one will be pasted into a Send box.
Examples:
did:namid:14w46h2at4w46h2at4w46h2at4w46h2at4w46h2at4w46h2at4w4snsj9a4
did:namid:testnet11:14w46h2at4w46h2at4w46h2at4w46h2at4w46h2at4w46h2at4w4snsj9a4
did:namid:testnet11:yourname.x
4. DID document
{
"@context": ["https://www.w3.org/ns/did/v1", "https://namid.net/ns/did/v1"],
"id": "did:namid:testnet11:1…",
"alsoKnownAs": ["namid:yourname.x", "did:namid:testnet11:yourname.x",
"did:chia:1…", "tld:1…", "namid:1…"],
"controller": "did:key:z6Mk…",
"verificationMethod": [{
"id": "did:namid:testnet11:1…#owner", "type": "Bls12381G1Key2020",
"controller": "did:namid:testnet11:1…", "publicKeyMultibase": "z…" }],
"authentication": ["did:namid:testnet11:1…#owner"],
"capabilityInvocation": ["did:namid:testnet11:1…#owner"],
"service": [
{ "id": "…#namid", "type": "NamIDName",
"serviceEndpoint": "https://namid.net/api/names/resolve?name=yourname.x" },
{ "id": "…#xch", "type": "ChiaPaymentAddress",
"serviceEndpoint": { "address": "txch1…", "network": "testnet11" } },
{ "id": "…#website", "type": "LinkedDomains", "serviceEndpoint": "https://yourname.example" },
{ "id": "…#dns", "type": "NamIDDNSRecords", "serviceEndpoint": { "records": [] } }
]
}
controlleris the holder's DID when the name is recorded as bound to one (did:keyordid:chia). It is absent when the name is controlled only by its owner key.verificationMethodcarries the name's BLS12-381 G1 owner key, theOWNER_PUBKEYcurried in its deed (whitepaper §3.2), when the resolver has it. The key signs record updates and key rotations and, when the deed is transferable, transfers.serviceentries are derived from the name's on-chain record set: the resolver endpoint, the XCH payment address, a linked website and DNS records. Nothing in the document is written by hand; it is a projection of the coin and its records.
DID document metadata (returned by resolution, not part of the document):
| key | meaning |
|---|---|
canonicalId |
the launcher form, once the coin exists |
equivalentId |
[the name form] |
versionId |
the current coin id of the singleton |
created / updated |
registry timestamps |
deactivated |
true after a lapse; always false for a soulbound name with renewal: never |
namid |
{name, root, lock_mode, renewal, issuer, namespace, mint_status, launcher_id, coin_id, record_sequence, expiry_block} — the protocol's own view (standards/ROOT-PROFILES.md) |
5. Operations
5.1 Create
A did:namid is created by creating the name:
- a root is won at the sealed-bid auction and minted as a soulbound DID deed in the settlement transaction (whitepaper §5.4);
- a name under a root is registered by one spend bundle that launches its DID deed and inserts its node into the root's on-chain registrar, signed and paid by the owner's wallet (whitepaper §8.9). Under an owner-only registrar only the root owner can add names (§8.6).
A name is registered only when it is on chain in its own coin, so both forms of the DID exist from the moment that
transaction confirms (mint_status: minted). No separate "DID registration" step exists: a name
that exists is a DID.
5.2 Read (resolve)
GET https://namid.net/api/did/resolve?did=<did>
GET https://namid.net/1.0/identifiers/<did> ; Universal Resolver driver shape
GET https://namid.net/api/did/method ; the method descriptor
The response is a DID Resolution Result (@context: https://w3id.org/did-resolution/v1)
with didDocument, didResolutionMetadata (contentType: application/did+ld+json,
retrieved, did, kind) and didDocumentMetadata (§4). Errors use the registered
names: invalidDid (400), notFound (404, including a network the resolver does not
serve), methodNotSupported (400).
A resolver MUST answer only with a record it can tie to the chain (the NamID
verify-or-refuse rule: /api/resolve carries the proof) or refuse; a client MAY verify the
singleton lineage itself against didDocumentMetadata.namid.launcher_id, from a Chia node alone, with the
chain-only client algorithm (whitepaper §11.1,
§11.4).
5.3 Update
Records (address, profile, DNS, services) are written signed by the key that controls the name and take effect
when the deed's update commits the new DATA_ROOT
(whitepaper §10.2); each update increments
record_sequence and, because it spends the deed, changes versionId. Keys rotate through the
announced, delayed and cancellable rotation (§3.5).
The DID string never changes on update.
5.4 Deactivate
- A termed name (a registrar with
TERM_BLOCKS > 0) that is not renewed lapses at itsEXPIRY; the document resolves withdeactivated: trueuntil the label is taken over, at which point a new deed and a new launcher-form DID exist (the name form resolves to the new one) (whitepaper §8.3). - A permanent name (
TERM_BLOCKS = 0,renewal: never) never lapses, and its deed can never be melted (§3.2): it is never deactivated. - A root is deactivated when its lease lapses and a re-auction opens; the winner receives a new deed with a new launcher id, and the lapsed coin persists with no standing (§6.3).
6. Security considerations
- Key compromise. The owner key authorises updates (and transfer, for transferable names). Every key change is public, delayed and cancellable, so a stolen key cannot quietly become the owner; without a separate recovery key a contested key can be delayed but not settled (whitepaper §3.5, §19).
- Root-owner key compromise. Under an owner-only registrar the root owner's key can add new names; it cannot move or alter existing ones, whose own owners sign every change. Every insert is a coin creation visible on chain (§8.6).
- Resolver trust. The resolver is a projection of chain state and says so: the
namid.launcher_idandversionIdin the metadata let any client verify the lineage independently. A resolver that cannot produce chain evidence refuses rather than guesses. - Address confusion.
did:namid:xch1…is invalid by grammar. - Network confusion. Mainnet omits the network segment; every other network names itself; a resolver answers only for the network it serves.
- Sanctions. Root allocation refuses labels on the protocol's OFAC-derived exact-name list
(
blocked-ofac.tsv, whitepaper §7). - Denial of service. Resolution is a read of a local index plus optional chain verification; the registry rate-limits per client address behind nginx.
7. Privacy considerations
- A DID document contains only what the holder chose to publish as records (address,
profile display, website, DNS). Rich records marked sensitive by the kind taxonomy
(
/api/records/kinds) are anchored by hash and never served in a document. - The name form makes a DID human-readable by design; a holder who wants an unlinkable identifier should not use a NamID name as one. The launcher form is pseudonymous but stable, and links every update of the same coin.
- The resolver does not log the caller beyond what rate limiting needs.
- Holders can correlate across services by choice (
alsoKnownAs), never by default.
8. Relationship to other identifiers
| form | what it is | in the document |
|---|---|---|
did:namid:… |
this method; canonical DID of a NamID | id |
namid:1… / namid:yourname.x |
the protocol's URI scheme (not a DID) | alsoKnownAs |
did:chia:1… |
the Chia-ecosystem spelling of the same launcher; not a registered method | alsoKnownAs |
tld:1… |
protocol-internal view | alsoKnownAs |
did:key:… / did:chia:… of the holder |
who the name is bound to | controller |
9. Profiles, and NFTs under a name
A DID document is what a wallet reads. A profile is the same subject as a person reads it, and this method defines one so that every venue renders a NamID the same way instead of inventing a face from the record.
GET /api/profile?name=yourname.x (or ?did=did:namid:…, either spelling)
GET /api/profile?holder=did:chia:1… the NAME behind an owner DID — the reverse lookup
GET /api/profile/card?name=yourname.x the small form a venue shows beside an owner
The holder form is the one a marketplace needs: it has an NFT's owner DID and wants to show
a name. The forward direction alone left every venue matching strings by hand.
The reply carries the identifiers of §3, the holder (controller), the payment address,
the lock and the issuer, holdings (other names the same identity holds, from the registry;
NFTs from a chain indexer when one answers), the full document and documentMetadata,
and a display block — title, avatar, bio,
self_attested: true.
display is self-attested: the holder wrote it. A conforming venue renders it as the
holder's words and never as a badge of its own. namid.net/p/<name> is the
canonical human page, and one reference badge file is served by every venue so a name looks identical
wherever it appears.
NFTs under a name
There is no separate “profile NFT” and nothing extra to mint: a NamID is the DID. An NFT minted by a holder binds to the name two ways, and a venue must check rather than read:
- On chain — the NFT1 coin's owner DID is the holder's
did:chia:1…, which is this document'scontroller. - Off chain — the metadata carries
"namid": "yourname.x"and"did_namid": "did:namid:…:1…", so a venue holding only the metadata can still resolve the name.
The claim holds when the NFT's owner DID equals the name's controller, or equals the
name's own DID. Anything else is an unverified claim and must be shown as a claim, or not at all. The check
lives in three places on purpose — registry, venue adapter and browser badge — because whoever prints the
badge must be able to derive it.
10. Conformance
An implementation conforms if it produces documents and resolution results as in §4–§5 for
every valid identifier in §3, refuses every invalid one with invalidDid, and never
answers a resolution it cannot tie to the chain. The reference implementation's test suite
(tests/test_did_namid.py, tests/test_namid_uri.py) is the conformance vector set.
NamID Protocol