Licensing API Integration Guide
This guide explains how to integrate Pulse Billing's licensing API into any application using the license/validate endpoint. This API allows you to validate license keys, check subscription status, and manage feature access across your products.
Overview
The Pulse Billing Licensing API provides a secure way to:
- Validate license tokens in real-time
- Check subscription status and billing periods
- Handle trial registrations and paid subscriptions
- Manage product-specific license validation
License Validation Endpoint
Endpoint
POST https://dcm-be.secureteam.net/licensing/validate
Request Format
{
"licenseToken": "string",
"productCodes": ["string"],
"authContext": "string"
}
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
licenseToken | string | Yes | The license token to validate |
productCodes | string[] | No | Array of product codes to validate against the license |
authContext | string | No | Unique identifier for tracking license usage (e.g., MAC address, machine ID) |
Response Format
Success Response (200 OK)
{
"isTrial": false,
"contact": {
"firstName": "John",
"lastName": "Doe",
"email": "[email protected]"
},
"productCode": "ACME_PRO",
"authStatus": "Success",
"companyName": "Acme Trading Corp"
}
Trial Response (200 OK)
{
"isTrial": true,
"contact": {
"firstName": "Jane",
"lastName": "Smith",
"email": "[email protected]"
},
"productCode": "NINJATRADER_BASIC",
"authStatus": "Success",
"companyName": "Trial Company"
}
Error Response (400 Bad Request)
{
"error": "license token field is required."
}
AuthStatus Values
| Status | Description |
|---|---|
Success | License is valid and active |
Failed | License validation failed |
Locked | Order is locked out |
Common Failure Reasons
- "Invalid license token" - License token not found in database
- "Invalid product code" - Product code doesn't match the license
- "Trial expired" - Trial period has ended
- "Order is locked" - Order has been locked out
- "No payment placed" - No payment activity found for the order
- "Subscription is due" - Subscription payment is overdue
Understanding authContext for License Protection
The authContext parameter is crucial for license misuse detection and protection. Pulse Billing tracks authentication events by authContext to identify when a license is being used across multiple machines or contexts simultaneously.
How License Misuse Detection Works
The system automatically monitors license usage patterns and blocks licenses when they're used across multiple machines:
- Tracking: Every validation request with
authContextis logged - Detection: Licenses are locked when used across multiple different
authContextvalues - Action: Misused licenses automatically receive
AuthStatus.Locked
Best Practices for authContext
Use Unique Machine Identifiers:
- MAC address (recommended)
- Machine ID or hardware fingerprint
- User-specific device identifier
- Session-based identifier (less secure)
Avoid These Patterns:
- Static values like "default" or "machine1"
- Values that change frequently (like IP addresses)
- Shared identifiers across multiple machines
Machine-Specific License Binding Examples
- JavaScript
- Python
- C#
// Get MAC address as authContext
const { exec } = require('child_process');
const { promisify } = require('util');
const execAsync = promisify(exec);
async function getMacAddress() {
try {
const { stdout } = await execAsync('getmac /v /fo csv');
const lines = stdout.split('\n');
if (lines.length > 1) {
const macLine = lines[1].split(',');
return macLine[0].replace(/"/g, '').trim();
}
} catch (error) {
console.error('Error getting MAC address:', error);
}
return null;
}
// Usage with MAC address
async function validateLicenseWithMac(licenseToken, productCodes) {
const macAddress = await getMacAddress();
const authContext = macAddress || 'fallback-machine-id';
const validator = new PulseLicenseValidator();
const result = await validator.validateLicense(licenseToken, productCodes, authContext);
if (result.valid) {
console.log(`License validated for machine: ${authContext}`);
return result;
} else {
console.error('License validation failed:', result.error);
return null;
}
}
// Alternative: Generate machine fingerprint
function generateMachineFingerprint() {
const os = require('os');
const crypto = require('crypto');
const machineInfo = {
hostname: os.hostname(),
platform: os.platform(),
arch: os.arch(),
cpus: os.cpus().length,
totalMemory: os.totalmem()
};
return crypto.createHash('sha256')
.update(JSON.stringify(machineInfo))
.digest('hex')
.substring(0, 16);
}
// Usage with machine fingerprint
const machineId = generateMachineFingerprint();
validator.validateLicense('LICENSE-TOKEN', ['ACME_PRO'], machineId);
import uuid
import hashlib
import subprocess
import platform
import os
def get_mac_address():
"""Get MAC address as authContext"""
try:
if platform.system() == "Windows":
result = subprocess.run(['getmac', '/v', '/fo', 'csv'],
capture_output=True, text=True)
if result.returncode == 0:
lines = result.stdout.strip().split('\n')
if len(lines) > 1:
mac_line = lines[1].split(',')
return mac_line[0].replace('"', '').strip()
else:
# Linux/Mac
import uuid
mac = uuid.UUID(int=uuid.getnode()).hex[-12:]
return ':'.join([mac[i:i+2] for i in range(0, 12, 2)])
except Exception as e:
print(f"Error getting MAC address: {e}")
return None
def generate_machine_fingerprint():
"""Generate unique machine fingerprint"""
machine_info = {
'hostname': platform.node(),
'system': platform.system(),
'machine': platform.machine(),
'processor': platform.processor(),
'platform': platform.platform(),
'python_version': platform.python_version()
}
# Create hash from machine info
info_string = str(sorted(machine_info.items()))
return hashlib.sha256(info_string.encode()).hexdigest()[:16]
# Usage examples
validator = PulseLicenseValidator()
# Option 1: Use MAC address
mac_address = get_mac_address()
if mac_address:
result = validator.validate_license(
license_token='LICENSE-TOKEN-HERE',
product_codes=['ACME_PRO'],
auth_context=mac_address
)
print(f"License validated for MAC: {mac_address}")
else:
print("Could not get MAC address")
# Option 2: Use machine fingerprint
machine_id = generate_machine_fingerprint()
result = validator.validate_license(
license_token='LICENSE-TOKEN-HERE',
product_codes=['ACME_PRO'],
auth_context=machine_id
)
print(f"License validated for machine: {machine_id}")
# Option 3: Combined approach (recommended)
auth_context = mac_address or machine_id or str(uuid.uuid4())
result = validator.validate_license(
license_token='LICENSE-TOKEN-HERE',
product_codes=['ACME_PRO'],
auth_context=auth_context
)
using System;
using System.Management;
using System.Security.Cryptography;
using System.Text;
using System.Net.NetworkInformation;
public class MachineIdentifier
{
public static string GetMacAddress()
{
try
{
var networkInterfaces = NetworkInterface.GetAllNetworkInterfaces();
foreach (var ni in networkInterfaces)
{
if (ni.NetworkInterfaceType == NetworkInterfaceType.Ethernet ||
ni.NetworkInterfaceType == NetworkInterfaceType.Wireless80211)
{
if (ni.OperationalStatus == OperationalStatus.Up)
{
return ni.GetPhysicalAddress().ToString();
}
}
}
}
catch (Exception ex)
{
Console.WriteLine($"Error getting MAC address: {ex.Message}");
}
return null;
}
public static string GenerateMachineFingerprint()
{
try
{
var machineInfo = new StringBuilder();
machineInfo.Append(Environment.MachineName);
machineInfo.Append(Environment.OSVersion);
machineInfo.Append(Environment.ProcessorCount);
machineInfo.Append(Environment.UserDomainName);
// Get additional hardware info on Windows
if (Environment.OSVersion.Platform == PlatformID.Win32NT)
{
try
{
using (var searcher = new ManagementObjectSearcher("SELECT * FROM Win32_Processor"))
{
foreach (ManagementObject obj in searcher.Get())
{
machineInfo.Append(obj["ProcessorId"]?.ToString());
break;
}
}
}
catch
{
// Fallback if WMI is not available
}
}
using (var sha256 = SHA256.Create())
{
var hash = sha256.ComputeHash(Encoding.UTF8.GetBytes(machineInfo.ToString()));
return Convert.ToHexString(hash).Substring(0, 16);
}
}
catch (Exception ex)
{
Console.WriteLine($"Error generating machine fingerprint: {ex.Message}");
return Guid.NewGuid().ToString("N")[..16];
}
}
public static string GetAuthContext()
{
// Try MAC address first, fallback to machine fingerprint
var macAddress = GetMacAddress();
if (!string.IsNullOrEmpty(macAddress))
{
return macAddress;
}
return GenerateMachineFingerprint();
}
}
// Usage examples
var validator = new PulseLicenseValidator();
// Option 1: Use MAC address
var macAddress = MachineIdentifier.GetMacAddress();
if (!string.IsNullOrEmpty(macAddress))
{
var result = await validator.ValidateLicenseAsync(
"LICENSE-TOKEN-HERE",
new[] { "ACME_PRO" },
macAddress
);
Console.WriteLine($"License validated for MAC: {macAddress}");
}
// Option 2: Use machine fingerprint
var machineId = MachineIdentifier.GenerateMachineFingerprint();
var result2 = await validator.ValidateLicenseAsync(
"LICENSE-TOKEN-HERE",
new[] { "ACME_PRO" },
machineId
);
Console.WriteLine($"License validated for machine: {machineId}");
// Option 3: Automatic selection (recommended)
var authContext = MachineIdentifier.GetAuthContext();
var result3 = await validator.ValidateLicenseAsync(
"LICENSE-TOKEN-HERE",
new[] { "ACME_PRO" },
authContext
);
Console.WriteLine($"License validated for context: {authContext}");
License Misuse Scenarios
Scenario 1: Legitimate Usage
Machine A (MAC: AA:BB:CC:DD:EE:FF): 5 validations
Total: 5 validations across 1 context
Result: ✅ License remains active
Scenario 2: License Misuse Detected
Machine A (MAC: AA:BB:CC:DD:EE:FF): 6 validations
Machine B (MAC: 11:22:33:44:55:66): 4 validations
Machine C (MAC: 99:88:77:66:55:44): 2 validations
Total: 12 validations across 3 contexts
Result: ❌ License locked due to misuse
Scenario 3: Unlocked License
Previous misuse detected and license locked
Admin unlocks license via dashboard
All previous authContext tracking is cleared
Result: ✅ License active, fresh start
Integration Examples
- JavaScript
- Python
- C#
class PulseLicenseValidator {
constructor(baseUrl = 'https://dcm-be.secureteam.net') {
this.baseUrl = baseUrl;
}
async validateLicense(licenseToken, productCodes = [], authContext = null) {
try {
const response = await fetch(`${this.baseUrl}/licensing/validate`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
licenseToken: licenseToken,
productCodes: productCodes,
authContext: authContext
})
});
const result = await response.json();
if (response.ok) {
// API returns boolean for /validate endpoint
return {
success: true,
valid: result,
data: result
};
} else {
return {
success: false,
valid: false,
error: result.error || 'Validation failed'
};
}
} catch (error) {
return {
success: false,
valid: false,
error: 'Network error'
};
}
}
async getDetailedValidation(licenseToken, productCodes = [], authContext = null) {
try {
const response = await fetch(`${this.baseUrl}/licensing/auth`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
licenseToken: licenseToken,
productCodes: productCodes,
authContext: authContext
})
});
const result = await response.json();
if (response.ok) {
return {
success: true,
data: result
};
} else {
return {
success: false,
error: result.error || 'Validation failed'
};
}
} catch (error) {
return {
success: false,
error: 'Network error'
};
}
}
}
// Usage example
const validator = new PulseLicenseValidator();
// Simple validation (returns boolean)
validator.validateLicense('LICENSE-TOKEN-HERE', ['ACME_PRO'], 'user-session-123')
.then(result => {
if (result.valid) {
console.log('License is valid');
enableFeatures();
} else {
console.error('License validation failed:', result.error);
handleInvalidLicense();
}
});
// Detailed validation (returns full response)
validator.getDetailedValidation('LICENSE-TOKEN-HERE', ['ACME_PRO'], 'user-session-123')
.then(result => {
if (result.success) {
const data = result.data;
console.log('License details:', data);
if (data.authStatus === 'Success') {
if (data.isTrial) {
console.log('Trial license for:', data.companyName);
} else {
console.log('Paid license for:', data.companyName);
}
enableFeatures();
} else {
console.log('License validation failed');
handleInvalidLicense();
}
} else {
console.error('Validation error:', result.error);
}
});
import requests
class PulseLicenseValidator:
def __init__(self, base_url='https://dcm-be.secureteam.net'):
self.base_url = base_url
self.session = requests.Session()
self.session.headers.update({
'Content-Type': 'application/json'
})
def validate_license(self, license_token, product_codes=None, auth_context=None):
"""Validate a license token (returns boolean)"""
if product_codes is None:
product_codes = []
payload = {
'licenseToken': license_token,
'productCodes': product_codes
}
if auth_context:
payload['authContext'] = auth_context
try:
response = self.session.post(
f'{self.base_url}/licensing/validate',
json=payload
)
if response.status_code == 200:
# API returns boolean for /validate endpoint
return {
'success': True,
'valid': response.json(),
'data': response.json()
}
else:
result = response.json()
return {
'success': False,
'valid': False,
'error': result.get('error', 'Validation failed')
}
except requests.RequestException as e:
return {
'success': False,
'valid': False,
'error': f'Network error: {str(e)}'
}
def get_detailed_validation(self, license_token, product_codes=None, auth_context=None):
"""Get detailed validation response"""
if product_codes is None:
product_codes = []
payload = {
'licenseToken': license_token,
'productCodes': product_codes
}
if auth_context:
payload['authContext'] = auth_context
try:
response = self.session.post(
f'{self.base_url}/licensing/auth',
json=payload
)
result = response.json()
if response.status_code == 200:
return {
'success': True,
'data': result
}
else:
return {
'success': False,
'error': result.get('error', 'Validation failed')
}
except requests.RequestException as e:
return {
'success': False,
'error': f'Network error: {str(e)}'
}
# Usage example
validator = PulseLicenseValidator()
# Simple validation (returns boolean)
result = validator.validate_license(
license_token='LICENSE-TOKEN-HERE',
product_codes=['ACME_PRO'],
auth_context='user-session-123'
)
if result['valid']:
print('License is valid')
enable_features()
else:
print('License validation failed:', result['error'])
handle_invalid_license()
# Detailed validation (returns full response)
detailed_result = validator.get_detailed_validation(
license_token='LICENSE-TOKEN-HERE',
product_codes=['ACME_PRO'],
auth_context='user-session-123'
)
if detailed_result['success']:
data = detailed_result['data']
print('License details:', data)
if data['authStatus'] == 'Success':
if data['isTrial']:
print(f'Trial license for: {data["companyName"]}')
else:
print(f'Paid license for: {data["companyName"]}')
enable_features()
else:
print('License validation failed')
handle_invalid_license()
else:
print('Validation error:', detailed_result['error'])
using System;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using System.Collections.Generic;
public class PulseLicenseValidator
{
private readonly HttpClient _httpClient;
private readonly string _baseUrl;
public PulseLicenseValidator(string baseUrl = "https://dcm-be.secureteam.net")
{
_baseUrl = baseUrl;
_httpClient = new HttpClient();
}
public async Task<LicenseValidationResult> ValidateLicenseAsync(string licenseToken, string[] productCodes = null, string authContext = null)
{
var request = new ValidationRequest
{
LicenseToken = licenseToken,
ProductCodes = productCodes ?? new string[0],
AuthContext = authContext
};
var json = JsonSerializer.Serialize(request);
var content = new StringContent(json, Encoding.UTF8, "application/json");
try
{
var response = await _httpClient.PostAsync($"{_baseUrl}/licensing/validate", content);
var responseContent = await response.Content.ReadAsStringAsync();
if (response.IsSuccessStatusCode)
{
var isValid = JsonSerializer.Deserialize<bool>(responseContent);
return new LicenseValidationResult
{
Success = true,
Valid = isValid
};
}
else
{
var errorResponse = JsonSerializer.Deserialize<ErrorResponse>(responseContent);
return new LicenseValidationResult
{
Success = false,
Valid = false,
Error = errorResponse.Error
};
}
}
catch (Exception ex)
{
return new LicenseValidationResult
{
Success = false,
Valid = false,
Error = $"Network error: {ex.Message}"
};
}
}
public async Task<DetailedValidationResult> GetDetailedValidationAsync(string licenseToken, string[] productCodes = null, string authContext = null)
{
var request = new ValidationRequest
{
LicenseToken = licenseToken,
ProductCodes = productCodes ?? new string[0],
AuthContext = authContext
};
var json = JsonSerializer.Serialize(request);
var content = new StringContent(json, Encoding.UTF8, "application/json");
try
{
var response = await _httpClient.PostAsync($"{_baseUrl}/licensing/auth", content);
var responseContent = await response.Content.ReadAsStringAsync();
if (response.IsSuccessStatusCode)
{
var result = JsonSerializer.Deserialize<ValidationResponse>(responseContent);
return new DetailedValidationResult
{
Success = true,
Data = result
};
}
else
{
var errorResponse = JsonSerializer.Deserialize<ErrorResponse>(responseContent);
return new DetailedValidationResult
{
Success = false,
Error = errorResponse.Error
};
}
}
catch (Exception ex)
{
return new DetailedValidationResult
{
Success = false,
Error = $"Network error: {ex.Message}"
};
}
}
}
public class ValidationRequest
{
public string LicenseToken { get; set; }
public string[] ProductCodes { get; set; }
public string AuthContext { get; set; }
}
public class ValidationResponse
{
public bool IsTrial { get; set; }
public ContactPerson Contact { get; set; }
public string ProductCode { get; set; }
public string AuthStatus { get; set; }
public string CompanyName { get; set; }
}
public class ContactPerson
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
}
public class ErrorResponse
{
public string Error { get; set; }
}
public class LicenseValidationResult
{
public bool Success { get; set; }
public bool Valid { get; set; }
public string Error { get; set; }
}
public class DetailedValidationResult
{
public bool Success { get; set; }
public ValidationResponse Data { get; set; }
public string Error { get; set; }
}
// Usage example
var validator = new PulseLicenseValidator();
// Simple validation (returns boolean)
var result = await validator.ValidateLicenseAsync(
"LICENSE-TOKEN-HERE",
new[] { "ACME_PRO" },
"user-session-123"
);
if (result.Valid)
{
Console.WriteLine("License is valid");
EnableFeatures();
}
else
{
Console.WriteLine("License validation failed:", result.Error);
HandleInvalidLicense();
}
// Detailed validation (returns full response)
var detailedResult = await validator.GetDetailedValidationAsync(
"LICENSE-TOKEN-HERE",
new[] { "ACME_PRO" },
"user-session-123"
);
if (detailedResult.Success)
{
var data = detailedResult.Data;
Console.WriteLine("License details:", data);
if (data.AuthStatus == "Success")
{
if (data.IsTrial)
{
Console.WriteLine($"Trial license for: {data.CompanyName}");
}
else
{
Console.WriteLine($"Paid license for: {data.CompanyName}");
}
EnableFeatures();
}
else
{
Console.WriteLine("License validation failed");
HandleInvalidLicense();
}
}
else
{
Console.WriteLine("Validation error:", detailedResult.Error);
}
Feature Management
Implementing Feature Gates
- JavaScript
- Python
- C#
class FeatureManager {
constructor(validationData) {
this.authStatus = validationData.authStatus;
this.isTrial = validationData.isTrial;
this.productCode = validationData.productCode;
this.companyName = validationData.companyName;
}
hasValidLicense() {
return this.authStatus === 'Success';
}
isTrialLicense() {
return this.isTrial === true;
}
canAccessFeature(featureName) {
if (!this.hasValidLicense()) {
return false;
}
// Define feature access based on product code and trial status
const featureAccess = {
'ACME_BASIC': {
'basic_indicators': true,
'standard_charts': true,
'premium_indicators': false,
'advanced_analytics': false
},
'ACME_PRO': {
'basic_indicators': true,
'standard_charts': true,
'premium_indicators': true,
'advanced_analytics': true
},
'ACME_ENTERPRISE': {
'basic_indicators': true,
'standard_charts': true,
'premium_indicators': true,
'advanced_analytics': true,
'custom_development': true,
'priority_support': true
}
};
const productFeatures = featureAccess[this.productCode] || {};
return productFeatures[featureName] === true;
}
getLicenseInfo() {
return {
valid: this.hasValidLicense(),
trial: this.isTrialLicense(),
product: this.productCode,
company: this.companyName
};
}
}
// Usage
const featureManager = new FeatureManager(validationData);
if (featureManager.hasValidLicense()) {
if (featureManager.isTrialLicense()) {
console.log('Using trial license');
showTrialLimitations();
}
if (featureManager.canAccessFeature('premium_indicators')) {
showPremiumIndicators();
}
if (featureManager.canAccessFeature('advanced_analytics')) {
showAdvancedAnalytics();
}
} else {
showLicenseExpiredMessage();
}
class FeatureManager:
def __init__(self, validation_data):
self.auth_status = validation_data['authStatus']
self.is_trial = validation_data['isTrial']
self.product_code = validation_data['productCode']
self.company_name = validation_data['companyName']
def has_valid_license(self):
return self.auth_status == 'Success'
def is_trial_license(self):
return self.is_trial == True
def can_access_feature(self, feature_name):
if not self.has_valid_license():
return False
# Define feature access based on product code and trial status
feature_access = {
'ACME_BASIC': {
'basic_indicators': True,
'standard_charts': True,
'premium_indicators': False,
'advanced_analytics': False
},
'ACME_PRO': {
'basic_indicators': True,
'standard_charts': True,
'premium_indicators': True,
'advanced_analytics': True
},
'ACME_ENTERPRISE': {
'basic_indicators': True,
'standard_charts': True,
'premium_indicators': True,
'advanced_analytics': True,
'custom_development': True,
'priority_support': True
}
}
product_features = feature_access.get(self.product_code, {})
return product_features.get(feature_name, False)
def get_license_info(self):
return {
'valid': self.has_valid_license(),
'trial': self.is_trial_license(),
'product': self.product_code,
'company': self.company_name
}
# Usage
feature_manager = FeatureManager(validation_data)
if feature_manager.has_valid_license():
if feature_manager.is_trial_license():
print('Using trial license')
show_trial_limitations()
if feature_manager.can_access_feature('premium_indicators'):
show_premium_indicators()
if feature_manager.can_access_feature('advanced_analytics'):
show_advanced_analytics()
else:
show_license_expired_message()
public class FeatureManager
{
private readonly string _authStatus;
private readonly bool _isTrial;
private readonly string _productCode;
private readonly string _companyName;
public FeatureManager(ValidationResponse validationData)
{
_authStatus = validationData.AuthStatus;
_isTrial = validationData.IsTrial;
_productCode = validationData.ProductCode;
_companyName = validationData.CompanyName;
}
public bool HasValidLicense()
{
return _authStatus == "Success";
}
public bool IsTrialLicense()
{
return _isTrial == true;
}
public bool CanAccessFeature(string featureName)
{
if (!HasValidLicense())
{
return false;
}
// Define feature access based on product code and trial status
var featureAccess = new Dictionary<string, Dictionary<string, bool>>
{
["ACME_BASIC"] = new Dictionary<string, bool>
{
["basic_indicators"] = true,
["standard_charts"] = true,
["premium_indicators"] = false,
["advanced_analytics"] = false
},
["ACME_PRO"] = new Dictionary<string, bool>
{
["basic_indicators"] = true,
["standard_charts"] = true,
["premium_indicators"] = true,
["advanced_analytics"] = true
},
["ACME_ENTERPRISE"] = new Dictionary<string, bool>
{
["basic_indicators"] = true,
["standard_charts"] = true,
["premium_indicators"] = true,
["advanced_analytics"] = true,
["custom_development"] = true,
["priority_support"] = true
}
};
if (featureAccess.TryGetValue(_productCode, out var productFeatures))
{
return productFeatures.TryGetValue(featureName, out var hasAccess) && hasAccess;
}
return false;
}
public LicenseInfo GetLicenseInfo()
{
return new LicenseInfo
{
Valid = HasValidLicense(),
Trial = IsTrialLicense(),
Product = _productCode,
Company = _companyName
};
}
}
public class LicenseInfo
{
public bool Valid { get; set; }
public bool Trial { get; set; }
public string Product { get; set; }
public string Company { get; set; }
}
// Usage
var featureManager = new FeatureManager(validationData);
if (featureManager.HasValidLicense())
{
if (featureManager.IsTrialLicense())
{
Console.WriteLine("Using trial license");
ShowTrialLimitations();
}
if (featureManager.CanAccessFeature("premium_indicators"))
{
ShowPremiumIndicators();
}
if (featureManager.CanAccessFeature("advanced_analytics"))
{
ShowAdvancedAnalytics();
}
}
else
{
ShowLicenseExpiredMessage();
}
License Caching
- JavaScript
- Python
- C#
class LicenseCache {
constructor() {
this.cache = new Map();
this.cacheTimeout = 24 * 60 * 60 * 1000; // 24 hours
}
getCachedLicense(licenseKey) {
const cached = this.cache.get(licenseKey);
if (cached && Date.now() - cached.timestamp < this.cacheTimeout) {
return cached.data;
}
return null;
}
setCachedLicense(licenseKey, data) {
this.cache.set(licenseKey, {
data: data,
timestamp: Date.now()
});
}
invalidateLicense(licenseKey) {
this.cache.delete(licenseKey);
}
}
import time
from typing import Dict, Optional, Any
class LicenseCache:
def __init__(self):
self.cache: Dict[str, Dict[str, Any]] = {}
self.cache_timeout = 24 * 60 * 60 # 24 hours in seconds
def get_cached_license(self, license_key: str) -> Optional[Dict]:
cached = self.cache.get(license_key)
if cached and time.time() - cached['timestamp'] < self.cache_timeout:
return cached['data']
return None
def set_cached_license(self, license_key: str, data: Dict) -> None:
self.cache[license_key] = {
'data': data,
'timestamp': time.time()
}
def invalidate_license(self, license_key: str) -> None:
self.cache.pop(license_key, None)
using System;
using System.Collections.Generic;
public class LicenseCache
{
private readonly Dictionary<string, CacheEntry> _cache;
private readonly TimeSpan _cacheTimeout;
public LicenseCache()
{
_cache = new Dictionary<string, CacheEntry>();
_cacheTimeout = TimeSpan.FromHours(24);
}
public ValidationResponse GetCachedLicense(string licenseKey)
{
if (_cache.TryGetValue(licenseKey, out var cached))
{
if (DateTime.UtcNow - cached.Timestamp < _cacheTimeout)
{
return cached.Data;
}
else
{
// Cache expired, remove it
_cache.Remove(licenseKey);
}
}
return null;
}
public void SetCachedLicense(string licenseKey, ValidationResponse data)
{
_cache[licenseKey] = new CacheEntry
{
Data = data,
Timestamp = DateTime.UtcNow
};
}
public void InvalidateLicense(string licenseKey)
{
_cache.Remove(licenseKey);
}
private class CacheEntry
{
public ValidationResponse Data { get; set; }
public DateTime Timestamp { get; set; }
}
}
Error Handling
Common Error Scenarios
| Scenario | Description | AuthStatus | Action |
|---|---|---|---|
| Invalid License Token | License token not found in database | Failed | Check license token format |
| Trial Expired | Trial period has ended | Failed | Prompt for purchase |
| Order Locked | Order has been locked out | Locked | Contact support |
| Invalid Product Code | Product code doesn't match license | Failed | Check product codes |
| No Payment | No payment activity found | Failed | Complete payment process |
| Subscription Due | Subscription payment is overdue | Failed | Prompt for renewal |
| Network Error | API request failed | N/A | Use cached data or enable limited mode |