Validate License
Validate a license artifact and check its current status.
Endpoint
POST /api/v1/v2/validate
Request
Headers
Authorization: Bearer ql_your_api_key
Content-Type: application/json
Body
Provide either artifact_compact or artifact_json:
{
"artifact_compact": "eyJ0eXAiOiAiUUwtTElDRU5TRSIsIC...",
"device_fingerprint": {
"cpu_id": "Intel-Core-i9-12900K",
"disk_serial": "WD-ABC123456",
"mac_address": "00:1A:2B:3C:4D:5E"
}
}
Or with full JSON:
{
"artifact_json": "{\"header\":{...},\"payload\":{...},\"signatures\":{...}}",
"device_fingerprint": null
}
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
artifact_compact | string | ⚡ | Compact license token (preferred) |
artifact_json | string | ⚡ | Full JSON artifact |
device_fingerprint | object | ❌ | Device properties for binding verification |
⚡ One of
artifact_compactorartifact_jsonis required.
Response
Success - Valid License (200 OK)
{
"is_valid": true,
"status": "valid",
"error": null,
"error_message": null,
"license_id": "b28a923a-c747-49b2-bc90-d87004c10379",
"entitlements": [
"feature:api",
"feature:export",
"seats:max"
],
"expires_at": "2026-12-30T15:30:00Z",
"in_grace_period": false,
"binding_verified": true,
"revocation_epoch": 5
}
Success - Invalid License (200 OK)
{
"is_valid": false,
"status": "expired",
"error": "EXPIRED",
"error_message": "License expired at 2025-01-15T00:00:00Z",
"license_id": "b28a923a-c747-49b2-bc90-d87004c10379",
"entitlements": [],
"expires_at": "2025-01-15T00:00:00Z",
"in_grace_period": false,
"binding_verified": false,
"revocation_epoch": 5
}
Response Fields
| Field | Type | Description |
|---|---|---|
is_valid | boolean | Whether the license is currently valid |
status | string | License status code |
error | string | Error code if invalid |
error_message | string | Human-readable error message |
license_id | string | Unique license identifier (JTI) |
entitlements | array | List of active entitlement IDs |
expires_at | datetime | License expiration timestamp |
in_grace_period | boolean | Whether license is in grace period |
binding_verified | boolean | Whether device binding was verified |
revocation_epoch | integer | Current revocation epoch |
Status Codes
| Status | Description | is_valid |
|---|---|---|
valid | License is active and valid | true |
grace_period | Expired but within grace period | true |
expired | Past expiration and grace period | false |
revoked | License has been revoked | false |
not_yet_valid | Before the nbf (not before) date | false |
binding_mismatch | Device fingerprint doesn't match | false |
signature_invalid | Cryptographic signature failed | false |
Error Codes
| Error | Description |
|---|---|
EXPIRED | License has expired |
REVOKED | License was administratively revoked |
NOT_YET_VALID | License activation date is in the future |
BINDING_MISMATCH | Device fingerprint doesn't match license |
SIGNATURE_INVALID | RSA or ML-DSA signature verification failed |
EPOCH_ROLLBACK | Revocation epoch is older than minimum |
Examples
Basic Validation
curl -X POST "https://quantumlock.softquantus.com/api/v1/v2/validate" \
-H "Authorization: Bearer ql_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"artifact_compact": "eyJ0eXAiOiAiUUwtTElDRU5TRSIsIC..."
}'
Validation with Device Binding
curl -X POST "https://quantumlock.softquantus.com/api/v1/v2/validate" \
-H "Authorization: Bearer ql_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"artifact_compact": "eyJ0eXAiOiAiUUwtTElDRU5TRSIsIC...",
"device_fingerprint": {
"cpu_id": "Intel-Core-i9-12900K",
"motherboard_serial": "MS-12345",
"disk_serial": "WD-ABC123456"
}
}'
Python SDK Example
from quantumlock_sdk import QuantumLockClient
client = QuantumLockClient(api_key="ql_your_api_key")
result = client.validate(
artifact_compact=stored_license_token,
device_fingerprint={
"cpu_id": get_cpu_id(),
"disk_serial": get_disk_serial()
}
)
if result.is_valid:
print(f"✅ License valid until {result.expires_at}")
if result.in_grace_period:
print("⚠️ License is in grace period - please renew!")
# Check specific entitlements
if "feature:api" in result.entitlements:
enable_api_access()
else:
print(f"❌ License invalid: {result.error_message}")
match result.error:
case "EXPIRED":
show_renewal_dialog()
case "REVOKED":
show_revoked_message()
case "BINDING_MISMATCH":
show_device_mismatch_error()
Best Practices
1. Cache Validation Results
Don't validate on every operation. Cache results for a reasonable period:
import time
CACHE_DURATION = 300 # 5 minutes
cached_result = None
cache_time = 0
def check_license(token):
global cached_result, cache_time
if cached_result and time.time() - cache_time < CACHE_DURATION:
return cached_result
cached_result = client.validate(artifact_compact=token)
cache_time = time.time()
return cached_result
2. Handle Grace Periods
Allow continued access during grace period but notify users:
if result.is_valid and result.in_grace_period:
days_left = (result.grace_until - datetime.now()).days
show_notification(f"License expires in {days_left} days. Please renew.")
3. Offline Fallback
Use StatusProofs for offline validation. See Status Proof.
Error Responses
400 Bad Request
{
"detail": "Must provide artifact_json or artifact_compact"
}
400 Parse Error
{
"detail": "Failed to parse artifact: Invalid base64 encoding"
}