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-modein_features.conf. - Production — live deployments.
dev-modemust 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
.waltlicensebundle 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.confmounted with the rest of the configuration filesLICENSE_STATE_ENCRYPTION_KEYset on every replica (at least 32 characters)- For online licenses: outbound access from the Enterprise API to walt.id's license service (
licenseServerUrl, typicallyhttps://license.walt.id) - For development licenses:
dev-modeenabled in_features.conf - For production licenses:
dev-modenot 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 (connected) activation
- Ask walt.id for an online license for this environment.
- Copy the returned OpenID credential offer.
- In
license.conf, set the license service URL and uncommentseedCredential:
licenseServerUrl = "https://license.walt.id"
seedCredential = "openid-credential-offer://..."
- Set
LICENSE_STATE_ENCRYPTION_KEYon the process (see License configuration). - 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)
- Edit
config/license.confwith the seed option above. - Pass the encryption key into the API service:
waltid-enterprise:
environment:
- LICENSE_STATE_ENCRYPTION_KEY={your-32-plus-character-secret}
- 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.
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.
ACTIVEmeans the stack is licensed.GRACEmeans an online license has expired but the stack is still serving traffic while it tries to renew.RESTRICTEDandUNLICENSEDblock new operations. - licenseId: String - Identifier of the bound license.
- organizationId: String - Organization the license was issued to.
- licenseType: String -
devorprod. - offline: Boolean -
truewhen 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:
| Method | Path | Purpose |
|---|---|---|
GET | /license/status | Current restriction, expiry, and warnings |
GET | /license/usage | Unsigned usage snapshot for monitoring |
GET | /license/usage-report | Signed usage report (SD-JWT VC) |
POST | /license/usage-report/export | Signed 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
/livezand license status, but other routes return503. - A newer mounted offline
.waltlicensebundle (laterissuedAt) 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/statusPOST /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
| Symptom | What to check |
|---|---|
| Startup fails with a blank seed | Set exactly one of seedCredential or seedCredentialFile on first start. |
| Startup fails because both seed options are set | Comment out one of them. |
LICENSE_STATE_ENCRYPTION_KEY is required / key too short | Set a value of at least 32 characters on every replica. |
License state decryption failed | The 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-mode | Add dev-mode to enabledFeatures in _features.conf, or use a production license. |
A PROD license cannot run with dev-mode enabled | Remove dev-mode from _features.conf. |
503 on API routes | Call 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.conf | The active license must also allow that feature. walt.id can disable features remotely. |
| Offline startup rejects the file | Confirm 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
- Get a license from walt.id (contact us).
- Configure
license.confandLICENSE_STATE_ENCRYPTION_KEYfor each deployment. - Start the API and confirm
GET /license/statusreturnsACTIVE. - For connected deployments, allow outbound access to walt.id's license service.
- For air-gapped deployments, export usage reports on the schedule walt.id gives you.
Next Steps
- License configuration —
license.conffields and the encryption key - Local Development — run the stack locally
- Kubernetes Deployment — production-style deploy
- Features —
_features.confanddev-mode
