Default Requests

If you create many DIDs on the same domain, most of each request is the same: the DID type, the domain, and the service endpoints in the DID Document. Default requests let you save that shared part once on your DID service, so each creation only carries what is unique to the DID.

Default requests are optional. Nothing on this page is required to create DIDs. Use it once you notice you are repeating the same did:web settings.

When This Is Worth It

Default requests pay off when a service creates many DIDs that share a setup and differ in a few fields. For the DID service that means:

  • did:web DIDs on one domain. Onboarding users under your domain. The type, domain and DID Document extras (such as a LinkedDomains service entry that ties the DID to your website) are the same every time. The key, the path and the DID ID are different every time. This is the case this page walks through.
  • A did:key format convention. did:key has one real option, useJwkJcsPub, which changes the format of the identifier. If your ecosystem needs one format everywhere, pin it once.

Two operations are a poor fit:

  • did:jwk has nothing to pin besides the key itself, and the key is different per DID.
  • Keys and paths. These identify the DID. A did:key and a did:jwk are derived from the key, and a did:web is derived from the domain and path. Storing them makes every DID the same DID (see Good to Know).

What Changes

Without a default, every did:web creation carries the full body:

{
  "type": "single_key_reference",
  "domain": "did.example.com",
  "serviceConfigurationSet": [
    {
      "type": "LinkedDomains",
      "serviceEndpoint": ["https://did.example.com"]
    }
  ],
  "keyReference": "waltid.tenant1.kms1.alice-key",
  "path": "tenant1/alice",
  "didId": "alice"
}

With the first three fields stored as a default, the call becomes:

{
  "keyReference": "waltid.tenant1.kms1.alice-key",
  "path": "tenant1/alice",
  "didId": "alice"
}

The service fills in everything you left out. Anything you do send in the call wins over the stored value.

Prerequisites

  • A DID service with a KMS attached. See Setup and Using KMS for DID Creation.
  • Optional: a DID store attached, if you want the created DIDs persisted under their didId.
  • A bearer token with the update-default-requests permission and the permission to create the DID type you are setting a default for. Both are needed to store a default.

Step 1: Store a Default

Store the shared settings with a PUT. The last part of the URL, create-did-web, names the API call the default applies to: the one behind POST /v1/{target}/did-service-api/dids/create/web. The body is an ordinary did:web creation request. Leave out every field that changes per DID, and always include type.

CURL

Endpoint: PUT /v1/{target}/did-service-api/dids/default-requests/create-did-web | API Reference

Example Request
curl -X 'PUT' \
  'https://{orgID}.enterprise-sandbox.waltid.dev/v1/{target}/did-service-api/dids/default-requests/create-did-web' \
  -H 'accept: application/json' \
  -H 'Authorization: Bearer {yourToken}' \
  -H 'Content-Type: application/json' \
  -d '{
  "type": "single_key_reference",
  "domain": "did.example.com",
  "serviceConfigurationSet": [
    {
      "type": "LinkedDomains",
      "serviceEndpoint": ["https://did.example.com"]
    }
  ]
}'

Path Parameters

  • orgID: String (required) - Organization host alias. For the sandbox organization test, the base URL is https://test.enterprise-sandbox.waltid.dev.
  • target: resourceIdentifier (required) - {organizationID}.{tenantID}.{didServiceID}, for example waltid.tenant1.did1.

Header Parameters

  • Authorization: String (required) - Bearer token. Format: Bearer {yourToken}.

Body Parameters

  • The body is a partial did:web creation request. It accepts the same fields as creating a did:web, and you can send a subset of them. type is required, because it selects the request shape; a body without it is rejected with 400. Unknown or misspelled keys are rejected now, not later when a DID is created. Missing values such as domain or the key are not checked until you create a DID.
Example Response 200 OK

The stored document is echoed back.

{
  "type": "single_key_reference",
  "domain": "did.example.com",
  "serviceConfigurationSet": [
    {
      "type": "LinkedDomains",
      "serviceEndpoint": ["https://did.example.com"]
    }
  ]
}

Response Codes

  • 200 - Default request stored.
  • 400 - The document is not a valid partial body for this operation.
  • 401 / 403 - Authentication or authorization failure. update-default-requests and the operation's own permission are both required.
  • 404 - Service not found, or the operation name is unknown.

Step 2: Create a DID

Send only what is specific to this DID: its key, its path and its ID.

CURL

Endpoint: POST /v1/{target}/did-service-api/dids/create/web | API Reference

Example Request
curl -X 'POST' \
  'https://{orgID}.enterprise-sandbox.waltid.dev/v1/{target}/did-service-api/dids/create/web' \
  -H 'accept: application/json' \
  -H 'Authorization: Bearer {yourToken}' \
  -H 'Content-Type: application/json' \
  -d '{
  "keyReference": "waltid.tenant1.kms1.alice-key",
  "path": "tenant1/alice",
  "didId": "alice"
}'

Path Parameters

  • orgID: String (required) - Organization host alias.
  • target: resourceIdentifier (required) - {organizationID}.{tenantID}.{didServiceID}.

Header Parameters

  • Authorization: String (required) - Bearer token. Format: Bearer {yourToken}.

Body Parameters

  • Any field you send overrides the stored value. The key (keyReference or key) is always needed, either in the default or in the call.
Example Response 201 Created

The DID is created on the stored domain, and its DID Document carries the stored LinkedDomains service entry. See Create a did:web for the full response.

{
  "id": "waltid.tenant1.did-store1.alice",
  "did": "did:web:did.example.com:tenant1:alice",
  "document": {
    "id": "did:web:did.example.com:tenant1:alice",
    "verificationMethod": [ ... ],
    "service": [
      {
        "id": "did:web:did.example.com:tenant1:alice#...",
        "type": "LinkedDomains",
        "serviceEndpoint": "https://did.example.com"
      }
    ]
  }
}

Response Codes

  • 201 - DID created.
  • 400 - The merged request is not a valid creation request, for example when neither the default nor the call provides a key.
  • 401 / 403 - Authentication or authorization failure.

Override Part of the Default

To change one thing, send only that. This request creates a DID on another domain and keeps the stored type and service entry:

{
  "keyReference": "waltid.tenant1.kms1.bob-key",
  "domain": "other.example.org",
  "path": "bob",
  "didId": "bob-other"
}

Pin the did:key Format

did:key creation has one option worth pinning, useJwkJcsPub. It defaults to true, which produces the jwk_jcs-pub form (did:key:z2dm…). Set it to false to produce the classic multibase form (did:key:zDna… for a P-256 key) on every creation.

CURL

Endpoint: PUT /v1/{target}/did-service-api/dids/default-requests/create-did-key | API Reference

Example Request
curl -X 'PUT' \
  'https://{orgID}.enterprise-sandbox.waltid.dev/v1/{target}/did-service-api/dids/default-requests/create-did-key' \
  -H 'accept: application/json' \
  -H 'Authorization: Bearer {yourToken}' \
  -H 'Content-Type: application/json' \
  -d '{
  "useJwkJcsPub": false
}'

Path Parameters

  • orgID: String (required) - Organization host alias.
  • target: resourceIdentifier (required) - {organizationID}.{tenantID}.{didServiceID}.

Body Parameters

  • A partial did:key creation request. Unlike did:web, it has no type field.
Example Response 200 OK
{
  "useJwkJcsPub": false
}

Response Codes

  • 200 - Default request stored.
  • 400 - The document is not a valid partial body for this operation.
  • 401 / 403 - Authentication or authorization failure.

Later POST …/dids/create/key calls only need keyReference and, if you store the DID, a didId.

Good to Know

  • Never store the key, the path or the didId. A DID is defined by them. Storing a path makes every DID did:web:…:{path}, and storing a key makes every did:key or did:jwk identical. The calls still succeed, each with 201, and the DID store ends up with several records for the same DID.
  • A stored key field follows you into other shapes. If the default holds keyReference and a call switches to type: "key_reference_set", the merged request contains both keyReference and keyReferenceSet and fails with 400 (unknown key). Store only the fields that every caller's shape has in common.
  • Same key, same did:key. Creating a did:key from one key twice yields the same identifier, whatever didId you use.
  • Defaults are not guardrails. Anyone allowed to create DIDs can override any stored field in their own call.
  • Each operation has its own default. create-did-web, create-did-key and create-did-jwk are separate.
  • Explicit values win, including false over a stored true. Arrays and primitives are replaced wholesale, so a call that sends serviceConfigurationSet replaces the stored list.

Read or Remove a Default

  • List all stored defaults: GET /v1/{target}/did-service-api/dids/default-requests (needs view-default-requests).
  • Read one: GET …/default-requests/create-did-web. Returns 404 if none is stored.
  • Remove one: DELETE …/default-requests/create-did-web. Returns 204, also when nothing was stored.

Full details, permissions and the other services that support default requests: Default Requests.

Last updated on September 29, 2026