Skip to content

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

FieldTypeDescription
tierstringLicense tier (basic, pro, enterprise, etc.)
product_idstringProduct identifier
issued_tostringCustomer identifier (email, company name, etc.)

Optional Fields

FieldTypeDescriptionDefault
expires_atstring (ISO 8601)Expiration timestampnull (never expires)
limitsobjectUsage limits{} (no limits)
max_activationsnumberMaximum concurrent activations1
notesstringInternal notesnull

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/stats

Rate 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