> For the complete documentation index, see [llms.txt](https://docs.empe.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.empe.io/develop/wallet-server/did-document-management.md).

# DID Document Management

The service can create Decentralized Identifiers (DIDs) and serve their DID documents. Two DID methods are created: **`did:key`** (a deterministic Ed25519 key-based DID) and **`did:web`** (a DID whose document is hosted by the service itself over HTTPS). A `did:web` document is stored server-side and published at a stable, UUID-keyed URL so that other parties can resolve it.

DIDs are used in two places:

* **Platform identities** for issuers and verifiers, created via the admin DID endpoints under `/agent`.
* **Holder (cloud-wallet) identities**, which are provisioned automatically when a holder is created.

All endpoints below require a valid OIDC JWT Bearer token (`Authorization: Bearer <token>`); the `/agent/*` routes additionally require the `admin` role. In development you can bypass auth with `AUTH_DISABLED=true`. The only exception is the public DID-document serving endpoint, which needs no auth.

## Create a did:key

Creates a deterministic Ed25519 key-based DID. No body is required.

**POST** `/agent/did/key`

### Response Body

* **did**: the generated DID, e.g. `did:key:z6Mk...`.
* **verificationMethodIds**: verification method identifiers usable for signing and assertions.

```
curl -X POST http://localhost:3000/agent/did/key \
  -H 'Authorization: Bearer <token>'
```

```json
{
  "did": "did:key:z6MkfWg...abc",
  "verificationMethodIds": ["did:key:z6MkfWg...abc#z6MkfWg...abc"]
}
```

## Create a did:web

Creates a DID whose document is hosted by the service. The DID is built as `did:web:<domain>:<uuid>`, where `<uuid>` is generated by the service and used as the public document path.

**POST** `/agent/did/web`

### Request Body

* **domain**: the hostname for the DID, without a scheme (e.g. `issuer.example.com`, optionally with a port such as `example.com:8080`). Required.

### Response Body

* **did**: the generated DID, e.g. `did:web:issuer.example.com:9b3c...`.
* **didDocument**: the full DID document JSON, including an Ed25519 verification method.

```
curl -X POST http://localhost:3000/agent/did/web \
  -H 'Authorization: Bearer <token>' \
  -H 'Content-Type: application/json' \
  -d '{"domain":"issuer.example.com"}'
```

```json
{
  "did": "did:web:issuer.example.com:9b3c1d2e-...",
  "didDocument": {
    "@context": [
      "https://www.w3.org/ns/did/v1",
      "https://w3id.org/security/suites/ed25519-2018/v1"
    ],
    "id": "did:web:issuer.example.com:9b3c1d2e-...",
    "verificationMethod": [
      {
        "id": "did:web:issuer.example.com:9b3c1d2e-...#key-1",
        "type": "Ed25519VerificationKey2018",
        "controller": "did:web:issuer.example.com:9b3c1d2e-...",
        "publicKeyBase58": "..."
      }
    ],
    "authentication": ["did:web:issuer.example.com:9b3c1d2e-...#key-1"],
    "assertionMethod": ["did:web:issuer.example.com:9b3c1d2e-...#key-1"]
  }
}
```

## Resolve a DID

Returns the DID document for a DID created through this service (`did:web` or `did:key`). If the DID was not created here, the endpoint returns `200` with a `null` body — it does not resolve external DIDs.

**GET** `/agent/did/:did`

```
curl http://localhost:3000/agent/did/did:key:z6MkfWg...abc \
  -H 'Authorization: Bearer <token>'
```

## List created DIDs

Returns the DIDs created through the service.

**GET** `/agent/dids`

```
curl http://localhost:3000/agent/dids \
  -H 'Authorization: Bearer <token>'
```

## Holder DIDs

A holder is a per-user cloud-wallet tenant. Its DID is provisioned when the holder is created, so there is no separate DID-generation step for holders. Choose the method at creation time.

**POST** `/agent/holder`

### Request Body

* **method**: `key` or `web`. Determines the DID method for the holder.
* **domain**: required when `method` is `web` (hostname, e.g. `example.com`).
* **label**: optional human-readable label for the wallet.

### Response Body

* **holderId**: internal holder identifier (UUID) used in wallet API calls.
* **did**: the holder's DID.
* **cryptographicBindingMethodsSupported**, **credentialSigningAlgValuesSupported**: capabilities of the holder wallet.
* **didDocument**: included only when `method` is `web`.

```
curl -X POST http://localhost:3000/agent/holder \
  -H 'Authorization: Bearer <token>' \
  -H 'Content-Type: application/json' \
  -d '{"method":"web","domain":"example.com","label":"User Wallet 1"}'
```

```json
{
  "holderId": "594b464b-20bd-495a-9fb6-87328c759629",
  "did": "did:web:example.com:594b464b-...",
  "cryptographicBindingMethodsSupported": ["did:key", "did:jwk", "did:web"],
  "credentialSigningAlgValuesSupported": ["EdDSA", "ES256"],
  "didDocument": { ... }
}
```

## Serve a hosted did:web document (public)

Every `did:web` created by the service (for an issuer, verifier, or holder) is published at a public, UUID-keyed path that matches the `<uuid>` segment of the DID. This endpoint requires no authentication and is exempt from rate limiting.

**GET** `/:uuid/did.json` **GET** `/:uuid/.well-known/did.json`

```
curl http://issuer.example.com/9b3c1d2e-.../did.json
```

If no document exists for the given UUID, the service returns `404` with the standard error body `{ statusCode, message, path, timestamp }`.

## Notes

* `did:web` documents are keyed by a service-generated UUID, not by any user identifier. The UUID is both the last segment of the DID and the document's public path.
* `did:key` and `did:web` verification methods use Ed25519 (`EdDSA`).
* The hostname for a `did:web` comes from the `domain` field of the create request, not from an environment variable (see [Environment & Setup](/develop/wallet-server/environment-and-setup.md) for the unused `DID_WEB_DOMAIN`/`DID_WEB_PATH` variables).
* `did:web` resolution requires HTTPS in production; for local testing only, `ALLOW_INSECURE_HTTP=true` permits plain HTTP.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.empe.io/develop/wallet-server/did-document-management.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
