License Models
Understanding the different types of licenses and how to use them.
Overview
QuantumLock™ supports flexible licensing models through the entitlement system. You can create any type of license by combining entitlements.
License Types
1. Subscription License
Time-limited license that requires periodic renewal.
# Create a 1-year subscription
artifact = client.create_license(
subject="customer:acme-corp",
valid_days=365,
grace_days=14,
entitlements=[
{"id": "tier:professional", "type": "tier", "value": "professional"},
{"id": "feature:all", "type": "feature", "value": True}
],
metadata={
"license_type": "subscription",
"renewal_url": "https://billing.example.com/renew"
}
)
Characteristics:
- Fixed expiration date
- Grace period for renewal
- Typically includes all features for tier
- Requires renewal workflow
2. Perpetual License
Never expires, but may have limited support/updates.
# Create perpetual license
# Using a far-future expiration (e.g., 100 years)
artifact = client.create_license(
subject="customer:acme-corp",
valid_days=36500, # ~100 years
grace_days=0,
entitlements=[
{"id": "tier:perpetual", "type": "tier", "value": "perpetual"},
{"id": "feature:core", "type": "feature", "value": True},
# Updates limited to 1 year
{
"id": "feature:updates",
"type": "feature",
"value": True,
"expires_at": "2026-12-30T00:00:00Z"
}
]
)
Characteristics:
- Very long or no expiration
- May have time-limited features (updates, support)
- One-time purchase model
3. Trial License
Short-term license for evaluation.
# Create 14-day trial
artifact = client.create_license(
subject="trial:user@example.com",
valid_days=14,
grace_days=0, # No grace for trials
entitlements=[
{"id": "tier:trial", "type": "tier", "value": "trial"},
{"id": "feature:all", "type": "feature", "value": True},
{"id": "limit:watermark", "type": "feature", "value": True}
],
metadata={
"license_type": "trial",
"upgrade_url": "https://buy.example.com"
}
)
Characteristics:
- Short duration (7-30 days)
- Full or limited features
- May include watermarks or limitations
- No grace period
4. Seat-Based License
Limited to a number of concurrent users.
# Create 50-seat license
artifact = client.create_license(
subject="customer:acme-corp",
valid_days=365,
entitlements=[
{"id": "tier:team", "type": "tier", "value": "team"},
{"id": "seats:max", "type": "quantity", "value": 50},
{"id": "seats:concurrent", "type": "quantity", "value": 50}
]
)
Characteristics:
- Quantity-based entitlements
- Requires seat tracking in your application
- May have concurrent vs. named user models
5. Usage-Based License
Limited by API calls, transactions, or other metrics.
# Create usage-based license
artifact = client.create_license(
subject="customer:acme-corp",
valid_days=365,
entitlements=[
{"id": "tier:usage", "type": "tier", "value": "usage"},
{"id": "quota:api_calls", "type": "quota", "value": 1000000},
{"id": "quota:storage_gb", "type": "quota", "value": 100}
]
)
Characteristics:
- Quota-based entitlements
- Requires usage tracking in your application
- May reset monthly or be lifetime
6. Node-Locked License
Bound to specific hardware.
# Create node-locked license
artifact = client.create_license(
subject="device:server-prod-01",
valid_days=365,
binding={
"type": "hardware",
"value": "sha256:...",
"properties": ["cpu_id", "motherboard_serial", "disk_serial"]
},
entitlements=[
{"id": "tier:server", "type": "tier", "value": "server"},
{"id": "feature:all", "type": "feature", "value": True}
]
)
Characteristics:
- Bound to hardware fingerprint
- Cannot be moved to different machine
- Requires device fingerprint during validation
7. Floating License
Pool of licenses that can be checked out.
# Create floating license pool
for i in range(10):
artifact = client.create_license(
subject=f"pool:acme-corp:seat-{i}",
valid_days=365,
entitlements=[
{"id": "tier:floating", "type": "tier", "value": "floating"},
{"id": "pool:id", "type": "metadata", "value": "acme-pool-1"}
]
)
Characteristics:
- Multiple licenses in a pool
- License server manages checkouts
- Maximum concurrent users = pool size
Entitlement Types
feature
Boolean feature flag.
{"id": "feature:api", "type": "feature", "value": True}
{"id": "feature:export", "type": "feature", "value": True}
{"id": "feature:admin", "type": "feature", "value": False}
quantity
Numeric limit.
{"id": "seats:max", "type": "quantity", "value": 50}
{"id": "projects:limit", "type": "quantity", "value": 10}
{"id": "storage:mb", "type": "quantity", "value": 5000}
quota
Usage-based limit (may reset).
{"id": "api:requests_monthly", "type": "quota", "value": 100000}
{"id": "reports:monthly", "type": "quota", "value": 100}
tier
Feature tier or plan level.
{"id": "tier:plan", "type": "tier", "value": "enterprise"}
module
Optional product module.
{"id": "module:analytics", "type": "module", "value": True}
{"id": "module:reporting", "type": "module", "value": True}
Checking Entitlements
Python SDK
result = client.validate(artifact_compact=token)
if result.is_valid:
# Check feature
if "feature:api" in result.entitlements:
enable_api()
# Check tier
tier = get_entitlement_value(result, "tier:plan")
if tier == "enterprise":
enable_enterprise_features()
# Check quantity
max_seats = get_entitlement_value(result, "seats:max")
if current_users > max_seats:
show_upgrade_prompt()
Helper Function
def get_entitlement_value(validation_result, entitlement_id):
"""Get the value of a specific entitlement."""
for ent in validation_result.entitlements_full:
if ent["id"] == entitlement_id:
return ent["value"]
return None
def has_feature(validation_result, feature_id):
"""Check if a feature is enabled."""
return f"feature:{feature_id}" in validation_result.entitlements
Grace Periods
Grace periods allow continued access after expiration:
artifact = client.create_license(
subject="customer:acme-corp",
valid_days=365,
grace_days=14 # 14-day grace after expiration
)
During grace period:
is_valid = Truein_grace_period = True- Show renewal warnings to user
result = client.validate(artifact_compact=token)
if result.is_valid:
if result.in_grace_period:
days_left = calculate_grace_remaining(result)
show_warning(f"License expired! {days_left} days to renew.")
Best Practices
1. Use Meaningful Entitlement IDs
# Good
{"id": "feature:sso", ...}
{"id": "module:analytics", ...}
{"id": "seats:max", ...}
# Bad
{"id": "f1", ...}
{"id": "ent_001", ...}
2. Include Tier Information
# Always include a tier for easy checking
{"id": "tier:plan", "type": "tier", "value": "enterprise"}
3. Set Appropriate Grace Periods
| License Type | Recommended Grace |
|---|---|
| Trial | 0 days |
| Monthly subscription | 3 days |
| Annual subscription | 14-30 days |
| Enterprise | 30-60 days |
4. Track Renewals
# Store renewal metadata
metadata = {
"original_license": "previous-license-id",
"renewal_count": 3,
"customer_since": "2022-01-15"
}
Migration from Other Systems
From Simple Key Systems
# Old: Single license key
# New: Create artifact with same features
old_key = "XXXX-XXXX-XXXX-XXXX"
customer_data = lookup_old_key(old_key)
new_artifact = client.create_license(
subject=f"migrated:{customer_data['email']}",
valid_days=customer_data['days_remaining'],
entitlements=convert_features(customer_data['features']),
metadata={
"migrated_from": old_key,
"migration_date": datetime.now().isoformat()
}
)
From Other Licensing Systems
- Export customer/license data from old system
- Map feature names to QuantumLock entitlements
- Create artifacts with equivalent expiration
- Update validation code to use new SDK
- Provide migration path for existing users