Create and manage DIDs
Create, inspect, update, and delete did:webvh identifiers on your WebVH Hosting appliance using the PNM CLI (pnm did-mgmt).
PNM connects to your VTA, which signs every version of a DID and publishes it to the appliance. For how a hosted DID is reserved, published, and deleted, see DID lifecycle.
A DID’s keys, service endpoints, and watchers stay as they were at creation until you publish a new version, and a retired service keeps resolving until you delete its DID.
Use this guide when:
- You want to create
did:webvhidentifiers for applications or services. - You need to inspect, update, or delete existing DIDs.
Prerequisites
- PNM CLI installed and configured against your VTA. The examples use your active VTA, shown by
pnm vta info. Add--vta <vta-slug>to target a different one. - Your appliance registered with your VTA under a server ID,
my-webvhin these examples. See Create your first hosted DID. - A VTA context for the application,
my-appin these examples, in which your DID has theadminrole. See the VTA guides Manage the contexts on a VTA and Grant and revoke access.
Every DID you create uses your appliance’s own domain, the host of its WebVH URL in Affinidi Portal, so leave out --domain.
Create a DID
pnm did-mgmt dids create \
--context my-app \
--server my-webvh \
--path my-service \
--label "My service identity"| Flag | Description |
|---|---|
--context | VTA context that owns the DID. |
--server | Server ID of your registered appliance, from pnm did-mgmt servers list. |
--path | Path for the DID on the appliance. A two-word path is generated when omitted. See the path rules below. |
--label | Optional human-readable label. |
--mediator-service | Adds your mediator as a DIDComm service endpoint, so the DID can receive DIDComm messages. |
--pre-rotation | Number of pre-rotation keys to generate. Default: 0. |
Path rules:
- Each segment is 2 to 63 lowercase letters, digits, or hyphens, starting and ending with a letter or digit.
- The first segment cannot be a reserved word such as
api,auth,dids,stats,acl, orhealth. .well-knownselects the appliance’s root DID slot, which is usually already taken by the appliance’s own DID.
On success, PNM prints WebVH DID created: followed by the new identifier on the DID: line, its context, server, mnemonic, SCID, portability, signing and key-agreement key IDs, and pre-rotation key count.
A self-hosted server can serve several domains. Run pnm did-mgmt dids list-domains --server <id> to see the domains your VTA may use, and pass --domain to choose one. See Hosting domains.
List DIDs
# Every DID known to your VTA
pnm did-mgmt dids list
# DIDs in one context, or on one appliance
pnm did-mgmt dids list --context my-app
pnm did-mgmt dids list --server my-webvhInspect a DID
Show a DID’s record, including its context, server, SCID, and log entry count:
pnm did-mgmt dids get did:webvh:Q1abc…:did.example.com:my-serviceRetrieve the DID’s did.jsonl log, including its current DID document. Add --out to write it to a file:
pnm did-mgmt dids get-log did:webvh:Q1abc…:did.example.com:my-service \
--out my-service.jsonlUpdate a DID
Each update publishes a new signed version of the DID, for example to change service endpoints, the pre-rotation count, watchers, or the TTL.
Edit interactively in your editor:
pnm did-mgmt dids edit --did did:webvh:Q1abc…:did.example.com:my-serviceAfter you save, PNM shows the document diff and asks whether to change each WebVH parameter: pre-rotation count, watchers, TTL, and audit label. It then asks you to confirm before it publishes the new version.
Or update from the command line:
# From a prepared DID document
pnm did-mgmt dids edit \
--did did:webvh:Q1abc…:did.example.com:my-service \
--document updated-document.json
# Change the TTL and the watcher set
pnm did-mgmt dids edit \
--did did:webvh:Q1abc…:did.example.com:my-service \
--ttl 86400 \
--watcher https://watcher.example.com| Flag | Effect |
|---|---|
--watcher | Replaces the whole watcher set. Repeat it for several watchers. |
--no-watchers | Turns watchers off. |
--options-file | Sets every parameter at once from a full update body, including witnesses. Use it instead of the per-field flags. |
--no-confirm | Skips the final publish prompt, for scripted runs. |
Delete a DID
pnm did-mgmt dids delete did:webvh:Q1abc…:did.example.com:old-servicePNM prints WebVH DID deleted: <did>.
- Effect: permanent. The appliance deletes the DID’s record, log, and any witness file. Export the log first with
get-logif you need an audit copy. - Dependencies: the VTA refuses to delete a DID that something else still depends on, and lists what to remove first.
- Unreachable appliance: the VTA still removes its own record, so the DID can be left behind on the appliance.
pnm did-mgmt dids reconcile --server my-webvhreports DIDs left behind, and requires an unrestricted admin on the VTA.
Confirm
Test 1: dids list shows the new DID
pnm did-mgmt dids list --context my-appExpected output: a table row with the DID, context my-app, and server my-webvh.
Test 2: request for the DID’s did.jsonl returns its signed log
The URL follows from the DID: https://<domain>/<path>/did.jsonl, where <domain> is the host of your appliance’s WebVH URL.
curl -s "https://did.example.com/my-service/did.jsonl"Expected output: the DID’s signed log, one JSON entry per line.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
Error: not found: webvh server not found: <id> | The --server value is not a registered server ID. | Run pnm did-mgmt servers list and use the registered ID. |
Error: forbidden: … on dids create | Your DID is not an admin of the context, or --domain names a domain other than the appliance’s. | Run pnm acl list --context my-app and confirm your DID has the admin role. Leave out --domain. |
webvh path already taken on the hosting server | Another DID already uses that path on the appliance. | Choose a different --path, or omit it to have one generated. |
| DID not resolving right after creation | Sync to the appliance’s edge is still in progress. | Wait a few seconds and retry. Contact Affinidi support if it still fails. |
edit rejected with the edited document changed the DID identifier | The id field was changed in the edited document. | Keep the id unchanged: it is fixed from the DID’s first log entry. |
Next steps
- Give a DID a human-readable name: make the DID reachable at
/@name. - Make a DID reachable over DIDComm: add your mediator as a service endpoint.
- Troubleshoot DID resolution: fix a DID that does not resolve.
Related
- Hosting domains: how a DID’s domain is chosen.
- Manage the contexts on a VTA: create and manage the contexts that own your DIDs.
- Grant and revoke access: control who can create DIDs in a context.
Glad to hear it! Please tell us how we can improve more.
Sorry to hear that. Please tell us how we can improve.
Thank you for sharing your feedback so we can improve your experience.