Issuing Licenses
Learn how to create and manage licenses using the License Server API's administrative endpoints.
Prerequisites
Before issuing licenses, ensure you have:
- License Server running and configured
- Admin API key properly set
- Understanding of your licensing model (tiers, limits, etc.)
Basic License Issuance
Issue a Simple License
Create a basic license with default settings:
bash
curl -X POST https://your-license-api.com/v1/issue-license \
-H "Authorization: Bearer $ADMIN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"tier": "basic",
"product_id": "your-product",
"issued_to": "customer@company.com"
}'Response:
json
{
"key": "7yChyZcfMG23Dx1sjBoLziPFrH4n-6f28",
"tier": "basic",
"product_id": "your-product",
"issued_to": "customer@company.com",
"issued_at": "2024-01-15T10:30:00Z",
"expires_at": null,
"limits": {},
"max_activations": 1
}Issue a License with Expiration
Create a time-limited license:
bash
curl -X POST https://your-license-api.com/v1/issue-license \
-H "Authorization: Bearer $ADMIN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"tier": "pro",
"product_id": "your-product",
"issued_to": "customer@company.com",
"expires_at": "2025-12-31T23:59:59Z"
}'Issue a License with Usage Limits
Create a license with specific usage constraints:
bash
curl -X POST https://your-license-api.com/v1/issue-license \
-H "Authorization: Bearer $ADMIN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"tier": "enterprise",
"product_id": "your-product",
"issued_to": "enterprise@company.com",
"expires_at": "2025-12-31T23:59:59Z",
"limits": {
"users": 500,
"api_calls": 100000,
"storage_gb": 1000
},
"max_activations": 10
}'License Parameters
Required Fields
| Field | Type | Description |
|---|---|---|
tier | string | License tier (basic, pro, enterprise, etc.) |
product_id | string | Product identifier |
issued_to | string | Customer identifier (email, company name, etc.) |
Optional Fields
| Field | Type | Description | Default |
|---|---|---|---|
expires_at | string (ISO 8601) | Expiration timestamp | null (never expires) |
limits | object | Usage limits | {} (no limits) |
max_activations | number | Maximum concurrent activations | 1 |
notes | string | Internal notes | null |
License Limits
Common limit types you can enforce:
json
{
"limits": {
"users": 100, // Maximum users
"api_calls": 10000, // API calls per month
"storage_gb": 50, // Storage in GB
"projects": 5, // Number of projects
"custom_limit": 1000 // Any custom metric
}
}Bulk License Issuance
Using a Script
For issuing multiple licenses, create a script:
javascript
const axios = require('axios');
class LicenseIssuer {
constructor(apiUrl, adminKey) {
this.apiUrl = apiUrl;
this.headers = {
'Authorization': `Bearer ${adminKey}`,
'Content-Type': 'application/json'
};
}
async issueLicense(licenseData) {
try {
const response = await axios.post(
`${this.apiUrl}/issue-license`,
licenseData,
{ headers: this.headers }
);
return response.data;
} catch (error) {
throw new Error(`Failed to issue license: ${error.response?.data?.error || error.message}`);
}
}
async issueBulkLicenses(licenses) {
const results = [];
for (const licenseData of licenses) {
try {
const license = await this.issueLicense(licenseData);
results.push({ success: true, license, data: licenseData });
console.log(`✓ Issued license for ${licenseData.issued_to}: ${license.key}`);
} catch (error) {
results.push({ success: false, error: error.message, data: licenseData });
console.error(`✗ Failed to issue license for ${licenseData.issued_to}: ${error.message}`);
}
}
return results;
}
}
// Usage
const issuer = new LicenseIssuer('https://your-license-api.com/v1', process.env.ADMIN_API_KEY);
const licenses = [
{
tier: 'basic',
product_id: 'your-product',
issued_to: 'customer1@company.com',
expires_at: '2025-12-31T23:59:59Z'
},
{
tier: 'pro',
product_id: 'your-product',
issued_to: 'customer2@company.com',
expires_at: '2025-12-31T23:59:59Z',
limits: { users: 50 }
}
// Add more licenses...
];
issuer.issueBulkLicenses(licenses)
.then(results => {
const successful = results.filter(r => r.success).length;
const failed = results.filter(r => !r.success).length;
console.log(`\nCompleted: ${successful} successful, ${failed} failed`);
});CSV Import Script
Import licenses from a CSV file:
python
import csv
import requests
import os
from datetime import datetime, timezone
class BulkLicenseIssuer:
def __init__(self, api_url, admin_key):
self.api_url = api_url
self.headers = {
'Authorization': f'Bearer {admin_key}',
'Content-Type': 'application/json'
}
def issue_license(self, license_data):
response = requests.post(
f'{self.api_url}/issue-license',
json=license_data,
headers=self.headers
)
response.raise_for_status()
return response.json()
def import_from_csv(self, csv_file_path):
results = []
with open(csv_file_path, 'r') as file:
reader = csv.DictReader(file)
for row in reader:
try:
# Convert CSV row to license data
license_data = {
'tier': row['tier'],
'product_id': row['product_id'],
'issued_to': row['issued_to']
}
# Add optional fields if present
if row.get('expires_at'):
license_data['expires_at'] = row['expires_at']
if row.get('max_activations'):
license_data['max_activations'] = int(row['max_activations'])
# Add limits if present
limits = {}
for key in ['users', 'api_calls', 'storage_gb']:
if row.get(key):
limits[key] = int(row[key])
if limits:
license_data['limits'] = limits
# Issue the license
license = self.issue_license(license_data)
results.append({
'success': True,
'license': license,
'row': row
})
print(f"✓ Issued license for {row['issued_to']}: {license['key']}")
except Exception as error:
results.append({
'success': False,
'error': str(error),
'row': row
})
print(f"✗ Failed to issue license for {row['issued_to']}: {error}")
return results
# Usage
issuer = BulkLicenseIssuer(
'https://your-license-api.com/v1',
os.getenv('ADMIN_API_KEY')
)
# Example CSV format:
# tier,product_id,issued_to,expires_at,max_activations,users,api_calls
# basic,my-product,user1@company.com,2025-12-31T23:59:59Z,1,10,1000
# pro,my-product,user2@company.com,2025-12-31T23:59:59Z,3,50,10000
results = issuer.import_from_csv('licenses.csv')
successful = len([r for r in results if r['success']])
failed = len([r for r in results if not r['success']])
print(f"\nCompleted: {successful} successful, {failed} failed")License Management
View License Details
Check the details of an issued license:
bash
curl "https://your-license-api.com/v1/export-license/7yChyZcfMG23Dx1sjBoLziPFrH4n-6f28"Revoke a License
Temporarily disable a license:
bash
curl -X POST https://your-license-api.com/v1/revoke-license \
-H "Authorization: Bearer $ADMIN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"key": "7yChyZcfMG23Dx1sjBoLziPFrH4n-6f28",
"revoked": true
}'Reactivate a License
Re-enable a revoked license:
bash
curl -X POST https://your-license-api.com/v1/revoke-license \
-H "Authorization: Bearer $ADMIN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"key": "7yChyZcfMG23Dx1sjBoLziPFrH4n-6f28",
"revoked": false
}'Best Practices
License Key Security
- Never log license keys in plain text
- Store admin API keys securely
- Use HTTPS for all license operations
- Implement audit logging for license operations
License Organization
- Use consistent product_id naming
- Include meaningful customer identifiers in issued_to
- Document your licensing tiers and limits
- Track license issuance in your customer database
Bulk Operations
- Process licenses in batches to respect rate limits
- Implement retry logic for failed operations
- Log all operations for audit purposes
- Validate data before issuing licenses
Monitoring
- Track license issuance rates
- Monitor for unusual patterns
- Set up alerts for failed operations
- Regular audits of active licenses
Troubleshooting
Common Issues
403 Unauthorized:
bash
# Verify your admin API key
curl -H "Authorization: Bearer $ADMIN_API_KEY" \
https://your-license-api.com/v1/admin/statsRate Limit Exceeded:
- Implement exponential backoff
- Batch operations appropriately
- Consider requesting rate limit increases
Invalid Parameters:
- Check required fields are present
- Validate date formats (ISO 8601)
- Ensure limits are positive numbers
Error Handling Example
javascript
async function issueLicenseWithRetry(licenseData, maxRetries = 3) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
const license = await issuer.issueLicense(licenseData);
return { success: true, license };
} catch (error) {
if (error.response?.status === 429) {
// Rate limit - wait and retry
const delay = Math.min(1000 * Math.pow(2, attempt), 10000);
console.log(`Rate limited, retrying in ${delay}ms...`);
await new Promise(resolve => setTimeout(resolve, delay));
continue;
}
if (error.response?.status >= 500 && attempt < maxRetries) {
// Server error - retry
console.log(`Server error, retrying (${attempt}/${maxRetries})...`);
continue;
}
// Don't retry client errors (4xx)
return { success: false, error: error.message };
}
}
return { success: false, error: 'Max retries exceeded' };
}Next Steps
- Learn about license activation tracking
- Set up usage monitoring
- Explore the API reference for complete endpoint documentation