Licensing

The walt.id Enterprise Stack is licensed software. A license from walt.id is required to run it.

This page shows you how to get a license, configure activation, start the stack, and stay in good standing. Field-level reference for license.conf is in License configuration.

The production Enterprise API image trusts only walt.id's compiled-in license issuer. You cannot point it at a customer-controlled license service.

Getting a License

If you are not a customer yet, contact walt.id.

Once you are a customer, walt.id provides:

  • Access to the private Enterprise Stack images
  • A license for each environment you run

Licenses are issued as development or production:

  • Development — local setup, evaluation, and non-production environments. Requires dev-mode in _features.conf.
  • Production — live deployments. dev-mode must be disabled.

Your agreement also determines which capabilities are included. Features outside your license are not available, even if they are enabled in _features.conf.

walt.id issues the license as one of:

  • An online OpenID credential offer (openid-credential-offer://...) for connected environments
  • An offline .waltlicense bundle plus a matching installation key for air-gapped environments
  • A raw signed license credential (SD-JWT VC) for controlled migration or recovery

Prerequisites

Before you activate, ensure you have:

  • A license from walt.id for this environment
  • MongoDB available to the Enterprise API (license state is stored there)
  • config/license.conf mounted with the rest of the configuration files
  • LICENSE_STATE_ENCRYPTION_KEY set on every replica (at least 32 characters)
  • For online licenses: outbound access from the Enterprise API to walt.id's license service (licenseServerUrl, typically https://license.walt.id)
  • For development licenses: dev-mode enabled in _features.conf
  • For production licenses: dev-mode not enabled

Share one encryption key across every replica of a deployment and back it up with MongoDB. A missing, too-short, or rotated key fails startup or makes stored license state unreadable. Live dual-key rotation is not supported.

Activate the License

Put license.conf in the API config directory (the enterprise quickstart already includes this file). Set licenseServerUrl to the URL walt.id gives you, then use exactly one seed option.

Online
Offline
Raw credential

Online (connected) activation

  1. Ask walt.id for an online license for this environment.
  2. Copy the returned OpenID credential offer.
  3. In license.conf, set the license service URL and uncomment seedCredential:
licenseServerUrl = "https://license.walt.id"
seedCredential = "openid-credential-offer://..."
  1. Set LICENSE_STATE_ENCRYPTION_KEY on the process (see License configuration).
  2. Start the Enterprise API. On first startup the stack redeems the offer, binds the credential to this installation, and stores both the credential and the installation key in MongoDB.

The offer is single-use. If activation fails after the offer was consumed, request a fresh offer from walt.id. Do not paste the same offer into another deployment.

Docker Compose (quickstart)

  1. Edit config/license.conf with the seed option above.
  2. Pass the encryption key into the API service:
waltid-enterprise:
  environment:
    - LICENSE_STATE_ENCRYPTION_KEY={your-32-plus-character-secret}
  1. Start the stack as in Local Development.

Docker

docker run -p 3000:3000 \
  -v $(pwd)/config:/config \
  -e LICENSE_STATE_ENCRYPTION_KEY="{your-32-plus-character-secret}" \
  waltid/waltid-enterprise-api

Kubernetes

Mount license.conf with the other config files. Store the encryption key (and optionally the online offer) in a Secret named waltid-enterprise-license. See License configuration and Kubernetes Deployment.

Confirm Activation

After the API is up, sign in as a super admin and call the license status endpoint.

Local development: the API is available at http://enterprise.localhost:3000. Use your deployment host in production.

CURL

Endpoint: GET /license/status

Example Request
curl -X 'GET' \
  'http://enterprise.localhost:3000/license/status' \
  -H 'accept: application/json' \
  -H 'Authorization: Bearer {yourToken}'

Header Parameters

  • Authorization: String (required) - Bearer token for a super admin session. Format: Bearer {yourToken}.

Example Response
{
  "restriction": "ACTIVE",
  "licenseId": "lic_abc123",
  "organizationId": "org_abc123",
  "licenseType": "prod",
  "offline": false,
  "features": ["*"],
  "usageLimits": {},
  "rateLimitPerHour": null,
  "disabledFeatures": [],
  "haltOnStartup": false,
  "expiresAt": 1893456000,
  "expiresInSeconds": 7776000,
  "expiringSoon": false,
  "warningMessage": null
}

Response Fields:

  • restriction: String - Operational state. ACTIVE means the stack is licensed. GRACE means an online license has expired but the stack is still serving traffic while it tries to renew. RESTRICTED and UNLICENSED block new operations.
  • licenseId: String - Identifier of the bound license.
  • organizationId: String - Organization the license was issued to.
  • licenseType: String - dev or prod.
  • offline: Boolean - true when this is an air-gapped license.
  • warningMessage: String - Present when the license is missing, restricted, in grace, or close to expiry.

🎉 You've activated the Enterprise Stack license when restriction is ACTIVE.

Related super-admin endpoints:

MethodPathPurpose
GET/license/statusCurrent restriction, expiry, and warnings
GET/license/usageUnsigned usage snapshot for monitoring
GET/license/usage-reportSigned usage report (SD-JWT VC)
POST/license/usage-report/exportSigned bundle for offline delivery to walt.id

After Activation

The stack stores the bound credential and installation key in MongoDB, encrypted with LICENSE_STATE_ENCRYPTION_KEY.

  • Later restarts reuse that persisted state. You do not redeem the online offer again.
  • All replicas of one deployment must share the same MongoDB and the same encryption key.
  • Do not scale the replica count above the licensed fleet size. Extra pods stay alive for /livez and license status, but other routes return 503.
  • A newer mounted offline .waltlicense bundle (later issuedAt) is treated as an explicit renewal.

Staying Licensed

Connected deployments periodically check in with walt.id. That check confirms the license is still valid, reports usage against your agreement, and lets walt.id disable a license or individual features if the contract requires it.

Allow outbound access from the Enterprise API to licenseServerUrl.

If the stack cannot reach walt.id for a short time, it keeps running while the cached credential is still valid or within grace (currently 24 hours after expiry for online licenses). After a longer outage, new operations are blocked until connectivity is restored or the license is renewed. Work already in progress is allowed to finish.

walt.id can also remotely restrict a license. When that happens, the API returns 503 with Enterprise API is unavailable because the license is not active. except for:

  • GET /livez
  • Login and logout
  • GET /license/status
  • POST /license/usage-report/export

Offline and Air-Gapped Environments

If your environment cannot reach walt.id, an offline license can be issued instead.

  • The stack does not need ongoing connectivity to stay licensed
  • Usage is still recorded locally
  • You send a signed usage report to walt.id on the schedule they give you (POST /license/usage-report/export)
  • As usage approaches the contractual limits in the license, the stack tightens automatically (rate limits, then some features, then a block on new billable operations)

If an offline license expires or its usage allowance is exhausted, new operations are blocked until walt.id issues a renewal. Mount the new bundle and restart (or roll) the API so the newer issuedAt is picked up.

Troubleshooting

SymptomWhat to check
Startup fails with a blank seedSet exactly one of seedCredential or seedCredentialFile on first start.
Startup fails because both seed options are setComment out one of them.
LICENSE_STATE_ENCRYPTION_KEY is required / key too shortSet a value of at least 32 characters on every replica.
License state decryption failedThe encryption key does not match the key that wrote MongoDB state. Restore the original key; do not rotate it in place.
Offer redemption fails / "already consumed"Request a fresh online offer from walt.id.
A DEV license requires dev-modeAdd dev-mode to enabledFeatures in _features.conf, or use a production license.
A PROD license cannot run with dev-mode enabledRemove dev-mode from _features.conf.
503 on API routesCall GET /license/status. If RESTRICTED or UNLICENSED, contact walt.id. Also confirm replica count is within the licensed fleet size.
Feature returns 403 even though it is enabled in _features.confThe active license must also allow that feature. walt.id can disable features remotely.
Offline startup rejects the fileConfirm the file is an offline license, the .waltlicense bundle checksum is intact, and installationKeyFile matches the key the bundle was bound to.

If the stack reports that it is unlicensed or restricted and the table above does not resolve it, contact walt.id.

What You Should Do

  1. Get a license from walt.id (contact us).
  2. Configure license.conf and LICENSE_STATE_ENCRYPTION_KEY for each deployment.
  3. Start the API and confirm GET /license/status returns ACTIVE.
  4. For connected deployments, allow outbound access to walt.id's license service.
  5. For air-gapped deployments, export usage reports on the schedule walt.id gives you.

Next Steps

Last updated on August 18, 2026