DID method · specification v0.2 · 20 October 2026

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) or did:namid:testnet11:1<bech32m>. The bech32m string after did: is exactly the protocol URI namid:1…: the human-readable part of the checksum is namid:, so did:namid:1… and namid: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 an equivalentId of 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 answers notFound for another.
  • Case — a did:namid identifier is lowercase; uppercase is invalid, not normalised.
  • Payment addresses are not identifiers — an id matching ^t?xch1[bech32]{20,}$ is invalid by grammar, because an xch1… 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": [] } }
  ]
}
  • controller is the holder's DID when the name is recorded as bound to one (did:key or did:chia). It is absent when the name is controlled only by its owner key.
  • verificationMethod carries the name's BLS12-381 G1 owner key, the OWNER_PUBKEY curried 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.
  • service entries 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 its EXPIRY; the document resolves with deactivated: true until 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_id and versionId in 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:

  1. On chain — the NFT1 coin's owner DID is the holder's did:chia:1…, which is this document's controller.
  2. 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.