---
title: "Tenant-level DIDs"
description: "Tenant-level DIDs are scoped to a specific tenant within the organization. Each tenant gets its own namespace in the DID path, which provides isolation between tenants — ideal for multi-tenant SaaS deployments where…"
stack: "Enterprise Stack (commercial) — version 1.1.1"
stack_version: "1.1.1"
stack_comparison: https://docs.walt.id/community-vs-enterprise.md
canonical_url: https://docs.walt.id/enterprise-stack/services/did-registry/tenant-level-did
generated: 2026-10-01
---
# Tenant-level DIDs

Tenant-level DIDs are scoped to a specific tenant within the organization. Each tenant gets its own namespace in the DID path, which provides isolation between tenants — ideal for multi-tenant SaaS deployments where each customer should have separate DIDs.

## When to use tenant-level DIDs

| Use tenant-level when… | Example |
|:-----------------------|:--------|
| Each tenant needs its own DID namespace | `did:web:domain.com:tenant-a:alice` |
| You want strict isolation between tenants | Tenant A cannot resolve Tenant B's DIDs by path |
| DIDs represent users or entities within a tenant | Per-user holder DIDs in a wallet tenant |

For organization-wide identities, use [Organization-level DIDs](https://docs.walt.id/enterprise-stack/services/did-registry/organization-level-did.md) instead.

## DID format and resolution

| | Value |
|:--|:------|
| **DID pattern** | `did:web:{domain}:{tenant}:{user}` |
| **Example DID** | `did:web:waltid.enterprise-sandbox.waltid.dev:users:bob` |
| **Resolution URL** | `https://waltid.enterprise-sandbox.waltid.dev/users/bob/did.json` |

When creating a DID via the DID Service, include the tenant name in the `path`:

```json
{
  "domain": "waltid.enterprise-sandbox.waltid.dev",
  "path": "users/bob"
}
```

See [Create a did:web](https://docs.walt.id/enterprise-stack/services/did-registry/create-did-web.md) for the full API.

The short resolution URL works by looking up the tenant's configured `didRegistry`: the first path segment (`{tenant}`) is matched against a tenant ID within the organization, and the request is resolved against that tenant's registry — see [Resolution → Tenant-relative resolution](https://docs.walt.id/enterprise-stack/services/did-registry/resolution.md#tenant-relative-resolution) for the underlying mechanism.

## Setup overview

Tenant-level DIDs require three steps:

1. **Create the DID Registry service** inside the tenant
2. **Configure the tenant** to reference that registry via `didRegistry`
3. **Create DIDs** with tenant-scoped paths

**Note:**

The `didRegistry` value is stored and read back by the tenant config endpoints exactly as given — no expansion happens there. At **resolution** time, though, it's tried both as given and expanded relative to the tenant, so either a full resource path (`{orgID}.{tenantID}.{serviceID}`, e.g. `waltid.users.did-registry-main`) or a short, tenant-relative service ID (e.g. `did-registry-main`) resolves correctly. The full path is still recommended, since it's what you'll see echoed back from config-view calls and is unambiguous at a glance.

```mermaid
flowchart TD
    A[Create DID Registry in tenant] --> B[Set didRegistry in tenant config]
    B --> C[Add DID Store as registry dependency]
    C --> D[Create DIDs with tenant/user paths]
    D --> E[DIDs resolve at https://domain/tenant/user/did.json]
```

## Step 1: Create the DID Registry Service

Create the registry inside the target tenant. Choose a service ID (e.g. `did-registry-main`) — you will reference the full path in the tenant configuration.

**Option: CURL**

Endpoint: `/v1/{target}/resource-api/services/create` | [API Reference](https://enterprise.sandbox.walt.id/swagger/index.html#/Service%20%7C%20Resource/post_v1__target__resource_api_services_create)

**Example Request**

```bash
curl -X 'POST' \
  'https://{orgID}.enterprise-sandbox.waltid.dev/v1/{target}/resource-api/services/create' \
  -H 'accept: */*' \
  -H 'Authorization: Bearer {yourToken}' \
  -H 'Content-Type: application/json' \
  -d '{
  "type": "did-registry"
}'
```

**Path Parameters**

- `orgID` — Organization base URL or host alias.
- `target` — _resourceIdentifier_ — Organization + tenant + service ID: `{organizationID}.{tenantID}.{serviceID}`, e.g. `waltid.users.did-registry-main`

**Body Parameters**

- `type` — _serviceType_ — Must be `did-registry`

---

**Response Codes**

- `201` — Service created successfully.

Then add the DID Store as a dependency — see [Setup → Step 3b](https://docs.walt.id/enterprise-stack/services/did-registry/setup.md#3b-attach-did-store-dependency).

## Step 2: Configure the tenant

Link the tenant to the DID Registry service. You can set this when creating a new tenant or update an existing one.

### Option A: Create a new tenant with registry configured

**Option: CURL**

Endpoint: `/v1/{target}/resource-api/tenants/create` | [API Reference](https://enterprise.sandbox.walt.id/swagger/index.html#/Service%20%7C%20Resource/post_v1__target__resource_api_tenants_create)

**Example Request**

```bash
curl -X 'POST' \
  'https://{orgID}.enterprise-sandbox.waltid.dev/v1/{target}/resource-api/tenants/create' \
  -H 'accept: */*' \
  -H 'Authorization: Bearer {yourToken}' \
  -H 'Content-Type: application/json' \
  -d '{
  "configuration": {
    "didRegistry": "waltid.users.did-registry-main"
  }
}'
```

**Path Parameters**

- `orgID` — Organization base URL.
- `target` — _resourceIdentifier_ — Organization + tenant ID: `{organizationID}.{tenantID}`, e.g. `waltid.users`

**Body Parameters**

- `configuration.didRegistry` — _String_ — Full resource path of the DID Registry service (matching Step 1). This is stored and read back exactly as given; a short ID like `"did-registry-main"` also resolves correctly (expanded relative to the tenant at resolution time), but the full path is recommended for clarity.

---

**Response Codes**

- `201` — Tenant created successfully.

### Option B: Update an existing tenant

Use the tenant config update endpoint to set `didRegistry` on an existing tenant. See [External DID Web Hosting → Step 2](https://docs.walt.id/enterprise-stack/services/did-registry/external-did-web-hosting.md#step-2-configure-tenant-level-did-registry) for the API.

## Step 3: Verify the configuration

Confirm the tenant points to the correct registry:

**Option: CURL**

Endpoint: `/v1/{target}/tenant-api/tenants/config/view` | [API Reference](https://enterprise.sandbox.walt.id/swagger/index.html#/Tenant%20Management/get_v1__target__tenant_api_tenants_config_view)

```bash
curl -X GET \
  'https://{orgID}.enterprise-sandbox.waltid.dev/v1/{target}/tenant-api/tenants/config/view' \
  -H 'accept: application/json' \
  -H 'Authorization: Bearer {yourToken}'
```

**Path Parameters**

- `orgID` — Organization base URL.
- `target` / `{tenant}` — Full tenant resource identifier, e.g. `waltid.users`

**Expected response:**

```json
{
  "didRegistry": "waltid.users.did-registry-main"
}
```

The response echoes back exactly what was stored in Step 2. Supplying the full resource path there is recommended for clarity — though a short, tenant-relative service ID also works at resolution time (see [Resolution → Tenant-relative resolution](https://docs.walt.id/enterprise-stack/services/did-registry/resolution.md#tenant-relative-resolution)).

## Step 4: Create and verify a DID

Create a `did:web` with a tenant-scoped path (see [Create a did:web](https://docs.walt.id/enterprise-stack/services/did-registry/create-did-web.md)), then verify resolution:

```bash
# Create the DID (via DID Service — path should be "{tenant}/user")
# Then verify:
curl https://waltid.enterprise-sandbox.waltid.dev/users/bob/did.json
```

## Next steps

- [Setup](https://docs.walt.id/enterprise-stack/services/did-registry/setup.md) — Base registry setup and DID Store dependency
- [Create a did:web](https://docs.walt.id/enterprise-stack/services/did-registry/create-did-web.md) — Generate tenant-scoped DIDs
- [External DID Web Hosting](https://docs.walt.id/enterprise-stack/services/did-registry/external-did-web-hosting.md) — Publish DIDs on a custom domain
