# Create and manage DIDs

> Create, inspect, update, and delete did:webvh identifiers on your WebVH Hosting appliance using the PNM CLI.

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](/products/affinidi-elements/webvh-hosting/concepts/did-lifecycle.md).

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:webvh identifiers 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-webvh in these examples. See [Create your first hosted DID](/products/affinidi-elements/webvh-hosting/get-started/create-your-first-did.md).

- A VTA context for the application, my-app in these examples, in which your DID has the admin role. See the VTA guides [Manage the contexts on a VTA](/products/affinidi-elements/vta/vta-management/manage-contexts.md) and [Grant and revoke access](/products/affinidi-elements/vta/vta-management/acl-management.md).

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

```bash
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, or health.

- .well-known selects 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.
Self-hosted deployments

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](/products/affinidi-elements/webvh-hosting/concepts/hosting-domains.md).

## List DIDs

```bash
# 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-webvh
```

## Inspect a DID

Show a DID’s record, including its context, server, SCID, and log entry count:

```bash
pnm did-mgmt dids get did:webvh:Q1abc…:did.example.com:my-service
```

Retrieve the DID’s did.jsonl log, including its current DID document. Add --out to write it to a file:

```bash
pnm did-mgmt dids get-log did:webvh:Q1abc…:did.example.com:my-service \
  --out my-service.jsonl
```

## Update 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:

```bash
pnm did-mgmt dids edit --did did:webvh:Q1abc…:did.example.com:my-service
```

After 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:

```bash
# 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

```bash
pnm did-mgmt dids delete did:webvh:Q1abc…:did.example.com:old-service
```

PNM 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-log if 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-webvh reports DIDs left behind, and requires an unrestricted admin on the VTA.

## Confirm

### Test 1: dids list shows the new DID

```bash
pnm did-mgmt dids list --context my-app
```

Expected 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.

```bash
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](/products/affinidi-elements/webvh-hosting/webvh-management/agent-names.md): make the DID reachable at /@name.

- [Make a DID reachable over DIDComm](/products/affinidi-elements/webvh-hosting/webvh-management/didcomm-endpoint.md): add your mediator as a service endpoint.

- [Troubleshoot DID resolution](/products/affinidi-elements/webvh-hosting/webvh-management/troubleshoot-resolution.md): fix a DID that does not resolve.

## Related

- [Hosting domains](/products/affinidi-elements/webvh-hosting/concepts/hosting-domains.md): how a DID’s domain is chosen.

- [Manage the contexts on a VTA](/products/affinidi-elements/vta/vta-management/manage-contexts.md): create and manage the contexts that own your DIDs.

- [Grant and revoke access](/products/affinidi-elements/vta/vta-management/acl-management.md): control who can create DIDs in a context.
