Skip to main content

Status Proof

Get cryptographic proofs for offline license validation.


Overview​

A StatusProof is a signed statement about a license's status at a specific point in time. It allows offline validation without contacting the server.

Use Cases​

  • Desktop applications without constant internet
  • Air-gapped systems
  • Edge devices with intermittent connectivity
  • Reducing API calls for cost optimization

Get Status Proof​

Endpoint​

POST /api/v1/v2/status-proof

Request​

{
"license_id": "b28a923a-c747-49b2-bc90-d87004c10379",
"device_fingerprint": {
"cpu_id": "Intel-Core-i9-12900K",
"disk_serial": "WD-ABC123456"
},
"ttl_hours": 48
}

Parameters​

ParameterTypeRequiredDescription
license_idstringβœ…License ID to get proof for
device_fingerprintobject❌Device properties to bind proof
ttl_hoursinteger❌Proof validity in hours (1-168, default: 24)

Response​

Success (200 OK)​

{
"proof": {
"license_id": "b28a923a-c747-49b2-bc90-d87004c10379",
"status": "valid",
"checked_at": "2025-12-30T15:30:00Z",
"valid_until": "2026-01-01T15:30:00Z",
"revocation_epoch": 42,
"binding_hash": "sha256:9f86d081884c7d659a2feaa0c55ad015...",
"entitlements": ["feature:api", "feature:export", "seats:max"],
"issuer_kid": "ql-api-v2",
"signature": "base64-encoded-signature..."
},
"compact": "eyJsaWNlbnNlX2lkIjogImIyOGE5...",
"valid_until": "2026-01-01T15:30:00Z"
}

Proof Fields​

FieldTypeDescription
license_idstringLicense ID the proof is for
statusstringLicense status at time of check
checked_atdatetimeWhen the proof was issued
valid_untildatetimeWhen the proof expires
revocation_epochintegerRevocation epoch at time of check
binding_hashstringHash of device fingerprint (if provided)
entitlementsarrayActive entitlements at time of check
issuer_kidstringKey ID used to sign the proof
signaturestringCryptographic signature

Status Values​

StatusDescription
validLicense is active
revokedLicense has been revoked
expiredLicense has expired
grace_periodLicense is in grace period

Examples​

Get Basic Proof​

curl -X POST "https://quantumlock.softquantus.com/api/v1/v2/status-proof" \
-H "Authorization: Bearer ql_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"license_id": "b28a923a-c747-49b2-bc90-d87004c10379",
"ttl_hours": 24
}'

Get Device-Bound Proof​

curl -X POST "https://quantumlock.softquantus.com/api/v1/v2/status-proof" \
-H "Authorization: Bearer ql_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"license_id": "b28a923a-c747-49b2-bc90-d87004c10379",
"device_fingerprint": {
"cpu_id": "Intel-Core-i9-12900K",
"motherboard_serial": "MS-12345",
"disk_serial": "WD-ABC123456"
},
"ttl_hours": 72
}'

Python SDK​

from quantumlock_sdk import QuantumLockClient
import json

client = QuantumLockClient(api_key="ql_your_api_key")

# Get a proof valid for 48 hours
proof = client.get_status_proof(
license_id="b28a923a-c747-49b2-bc90-d87004c10379",
device_fingerprint={
"cpu_id": get_cpu_id(),
"disk_serial": get_disk_serial()
},
ttl_hours=48
)

# Store for offline use
with open("proof_cache.json", "w") as f:
json.dump({
"proof": proof.to_dict(),
"compact": proof.compact,
"valid_until": proof.valid_until.isoformat()
}, f)

print(f"Proof valid until: {proof.valid_until}")

Offline Validation​

Use cached proofs to validate licenses offline:

Python SDK​

from quantumlock_sdk import OfflineValidator, StatusProof
import json
from datetime import datetime

# Load cached data
with open("proof_cache.json", "r") as f:
cache = json.load(f)

with open("license.qlf", "r") as f:
license_data = json.load(f)

# Create validator with cached public keys
validator = OfflineValidator(public_keys=cached_public_keys)

# Parse proof
proof = StatusProof.from_dict(cache["proof"])

# Validate
result = validator.validate_offline(
artifact=license_data,
proof=proof,
device_fingerprint={
"cpu_id": get_cpu_id(),
"disk_serial": get_disk_serial()
}
)

if result.is_valid:
print("βœ… License valid (offline validation)")
print(f" Status: {result.status}")
print(f" Proof expires: {proof.valid_until}")
else:
print(f"❌ Validation failed: {result.error}")

Validation Flow​

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ OFFLINE VALIDATION β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ β”‚
β”‚ 1. Load cached proof and license β”‚
β”‚ ↓ β”‚
β”‚ 2. Check proof expiration β”‚
β”‚ ↓ β”‚
β”‚ 3. Verify proof signature β”‚
β”‚ ↓ β”‚
β”‚ 4. Check license ID matches proof β”‚
β”‚ ↓ β”‚
β”‚ 5. Verify device fingerprint (if bound) β”‚
β”‚ ↓ β”‚
β”‚ 6. Check revocation epoch β”‚
β”‚ ↓ β”‚
β”‚ 7. Return validation result β”‚
β”‚ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Best Practices​

1. Refresh Proofs Before Expiration​

from datetime import datetime, timedelta

def should_refresh_proof(proof):
"""Refresh when 75% of TTL has passed."""
total_ttl = proof.valid_until - proof.checked_at
threshold = proof.checked_at + (total_ttl * 0.75)
return datetime.utcnow() > threshold

if should_refresh_proof(cached_proof):
try:
new_proof = client.get_status_proof(license_id)
save_proof(new_proof)
except NetworkError:
# Continue with existing proof
pass

2. Bind Proofs to Devices​

Device binding prevents proof reuse on different machines:

proof = client.get_status_proof(
license_id=license_id,
device_fingerprint=get_device_fingerprint()
)

3. Cache Multiple Proof Durations​

For applications with varying connectivity:

# Short-lived proof for online scenarios
short_proof = client.get_status_proof(license_id, ttl_hours=1)

# Long-lived proof for offline scenarios
long_proof = client.get_status_proof(license_id, ttl_hours=168)

Error Responses​

404 Not Found​

{
"detail": "License not found: b28a923a-c747-49b2-bc90-d87004c10379"
}

400 Bad Request​

{
"detail": "ttl_hours must be between 1 and 168"
}

Security Considerations​

  1. Proof Expiration: Short TTLs are more secure but require more frequent renewals
  2. Device Binding: Prevents proof reuse but requires consistent fingerprinting
  3. Revocation Epoch: Always verify the epoch hasn't been rolled back
  4. Signature Verification: Always verify the proof signature before trusting it