API Documentation

Complete reference for the License Validator API

License Validation

POST/api/validate

Validate a license key with device fingerprint

Request Body

{
  "licenseKey": "XXXX-XXXX-XXXX-XXXX",
  "fingerprint": "unique-device-identifier"
}

Success Response (200)

{
  "valid": true,
  "license": {
    "name": "Customer License",
    "expiresAt": "2025-12-31T00:00:00.000Z"
  }
}

Error Response

{
  "valid": false,
  "error": "License not found"
}

Common Error Messages

  • 404License not found
  • 403License is disabled
  • 403License has expired
  • 403Maximum activations reached

Quick Test with cURL

curl -X POST https://yourdomain.com/api/validate \
  -H "Content-Type: application/json" \
  -d '{
    "licenseKey": "YOUR-LICENSE-KEY-HERE",
    "fingerprint": "test-device-123"
  }'

Offline License Validation

Validate licenses without internet connectivity using cryptographic signatures and hardware binding.

What is Offline Validation?

Offline validation allows your application to verify license keys locally without an internet connection. Each offline key contains cryptographically signed license data that can be verified client-side.

  • No internet required for validation
  • Hardware-bound at generation time
  • Cryptographic HMAC-SHA256 signatures
  • Works in air-gapped environments

Online vs Offline Validation

FeatureOnlineOffline
Internet RequiredYesNo
Hardware BindingAt first activationAt generation
RevocationImmediateOnly at expiration
Speed50-300ms<1ms
Use CaseConnected appsAir-gapped systems

Getting Offline License Keys

GET/api/licenses/[id]/offline

Retrieve offline key and verification secret

Success Response

{
  "offlineLicenseKey": "eyJsaWQ...-a8f2...",
  "boundFingerprint": "abc123...",
  "verificationSecret": "def456...",
  "format": {
    "description": "Offline key format: ENCODED_DATA.SIGNATURE",
    "usage": "Validate locally without internet",
    "binding": "Bound to device: abc123..."
  }
}

Client-Side Validation

Use the code samples below to validate offline keys in your application:

JavaScript/Node.js

const validator = new LicenseValidator(
  'https://yourapi.com',
  'verification-secret-here'
);

const offlineKey = 'eyJsaWQ...-a8f2...';
const result = validator.validateOffline(offlineKey);

if (result.valid) {
  console.log('Valid offline license!');
} else {
  console.log('Invalid:', result.error);
}

💡 Best Practice: Use the hybrid validation approach with validateWithFallback() to try offline first, then fall back to online if offline fails.

Security Considerations

  • The verification secret is safe to distribute with your application
  • Offline keys cannot be revoked remotely - they only expire
  • Keys are cryptographically bound to device fingerprints
  • Tampering with keys causes validation to fail
  • Always set expiration dates for offline licenses

Technical Details

Signature Algorithm

HMAC-SHA256

Encoding

Base64url

Key Length

~40-60 characters

Validation Speed

<1ms (local)

Multi-Product Support

Manage licenses for multiple software products within a single account.

Overview

Multi-product support allows you to organize your licenses by product, making it easier to manage multiple applications or software offerings from a single dashboard.

  • Create separate products for each application (Desktop, Mobile, Web)
  • Filter licenses by product
  • Set a default product for quick access
  • Add custom icons and descriptions

Creating a Product

POST /api/products
Content-Type: application/json

{
  "name": "My Desktop App",
  "description": "Desktop application for Windows and Mac",
  "icon": "🚀",
  "isDefault": true
}

Or create products directly from the dashboard at /products

Creating Licenses for a Product

POST /api/licenses
Content-Type: application/json

{
  "name": "Pro License",
  "productId": "prod_abc123",
  "maxActivations": 5,
  "expiresAt": "2027-12-31T23:59:59Z"
}

Managing Products

List Products

GET /api/products

Update Product

PATCH /api/products/:id

Delete Product

DELETE /api/products/:id

Note: Cannot delete the default product

💡 Pro Tip: Existing licenses are automatically migrated to a “Default Product” for backward compatibility.

Feature-Based Entitlements

Control which features each license can access with granular feature flags.

Overview

Feature entitlements allow you to create tiered licensing models by enabling or disabling specific features per license. This is perfect for Basic/Pro/Enterprise pricing tiers.

Creating a License with Features

POST /api/licenses
Content-Type: application/json

{
  "name": "Pro License",
  "features": ["analytics", "export", "api"],
  "maxActivations": 5,
  "expiresAt": "2027-12-31T23:59:59Z"
}

Standard Validation (includes features)

The standard validation endpoint now returns enabled features:

POST /api/validate
Content-Type: application/json

{
  "licenseKey": "XXXX-XXXX-XXXX-XXXX",
  "fingerprint": "device-id"
}

// Response:
{
  "valid": true,
  "license": {
    "key": "XXXX-XXXX-XXXX-XXXX",
    "features": ["analytics", "export", "api"],
    "expiresAt": "2027-12-31T23:59:59Z",
    ...
  }
}

Feature Validation Endpoint

Check if a license has access to a specific feature:

POST /api/licenses/validate-feature
Content-Type: application/json

{
  "licenseKey": "XXXX-XXXX-XXXX-XXXX",
  "feature": "analytics",
  "fingerprint": "device-id" // optional
}

// Response (has access):
{
  "valid": true,
  "feature": "analytics",
  "hasAccess": true,
  "enabledFeatures": ["analytics", "export", "api"]
}

// Response (no access):
{
  "valid": true,
  "feature": "webhooks",
  "hasAccess": false,
  "enabledFeatures": ["analytics", "export"]
}

Common Features

analytics

Analytics and reporting

export

Data export capabilities

api

API access

webhooks

Webhook integrations

custom_branding

White-label features

priority_support

Priority customer support

Wildcard Access

Grant access to all features (current and future) using the wildcard:

{
  "features": ["*"]  // Grants all features
}

Client-Side Implementation

// Validate license and check features
const response = await fetch('/api/validate', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    licenseKey: 'XXXX-XXXX-XXXX-XXXX',
    fingerprint: getDeviceFingerprint()
  })
});

const data = await response.json();

if (data.valid) {
  const features = data.license.features;
  
  // Enable features based on license
  if (features.includes('analytics')) {
    enableAnalytics();
  }
  
  if (features.includes('export')) {
    enableExport();
  }
}

// Or check a specific feature
const featureCheck = await fetch('/api/licenses/validate-feature', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    licenseKey: 'XXXX-XXXX-XXXX-XXXX',
    feature: 'api'
  })
});

const featureData = await featureCheck.json();
if (featureData.hasAccess) {
  enableAPIAccess();
}

⚠️ Security Note: Always validate features server-side. Never trust client-only feature checks as they can be manipulated.

Feature Naming Best Practices

  • Use lowercase with underscores: api_access
  • Be descriptive and clear: priority_support
  • Avoid spaces, hyphens, or camelCase
  • Plan your feature names upfront for consistency

Customer Management

Organize licenses by assigning them to customers or companies.

Benefits

  • Track which licenses belong to which customer
  • Store customer contact information and notes
  • View all licenses assigned to a specific customer
  • Organize licenses by company for better management

Creating a Customer

Create a customer profile with company details:

POST /api/customers
Content-Type: application/json

{
  "name": "Acme Corporation",
  "email": "contact@acme.com",
  "contactPerson": "John Doe",
  "phone": "+1 (555) 123-4567",
  "address": "123 Main St, City, State, ZIP",
  "notes": "Enterprise customer - priority support"
}

Assigning Licenses

Assign a license to a customer when creating:

POST /api/licenses
Content-Type: application/json

{
  "name": "Production License",
  "maxActivations": 5,
  "customerId": "customer-id-here",
  "expiresAt": "2025-12-31T23:59:59Z"
}

Or update an existing license:

PATCH /api/licenses
Content-Type: application/json

{
  "id": "license-id-here",
  "customerId": "customer-id-here"
}

Viewing Customer Details

Get a customer with all assigned licenses:

GET /api/customers/{customer-id}

Response:
{
  "id": "customer-id",
  "name": "Acme Corporation",
  "email": "contact@acme.com",
  "contactPerson": "John Doe",
  "phone": "+1 (555) 123-4567",
  "licenses": [
    {
      "id": "license-id",
      "licenseKey": "XXXX-XXXX-XXXX-XXXX",
      "name": "Production License",
      "isActive": true,
      "currentActivations": 2,
      "maxActivations": 5
    }
  ]
}

Using License Templates

Templates allow you to create reusable license configurations for quick license generation.

What are Templates?

License templates are pre-configured settings that you can reuse to quickly generate multiple licenses with the same properties. Instead of manually entering license details every time, create a template once and use it repeatedly.

Use Cases:

  • • Standard customer licenses (e.g., "Professional Plan")
  • • Trial licenses with 30-day expiration
  • • Enterprise licenses with unlimited activations
  • • Different product tiers with varying limits

How Templates Work

  1. 1
    Create a Template: Define settings like max activations, expiration days, and metadata. Give it a descriptive name like "Standard Annual License".
  2. 2
    Apply Template: Use the template to generate one or more licenses. Each license gets a unique key but shares the template's settings.
  3. 3
    Quick Create: From the dashboard, use the "Quick Create from Template" dropdown to instantly generate licenses from your saved templates.

Template Properties

PropertyDescription
nameTemplate name (e.g., "Pro Plan Template")
maxActivationsMax devices that can use licenses from this template
expirationDaysDays until license expires (from creation date)
metadataCustom JSON data (product tier, features, etc.)

API Examples

Create a Template

POST /api/templates

{
  "name": "Professional Annual",
  "maxActivations": 5,
  "expirationDays": 365,
  "metadata": {
    "tier": "professional",
    "features": ["analytics", "priority-support"]
  }
}

Generate Licenses from Template

POST /api/templates/{templateId}/apply

{
  "name": "Acme Corp License",
  "count": 10  // Generate 10 licenses
}

// Response: 10 licenses with identical settings but unique keys

Using Webhooks

Webhooks let you receive real-time notifications when license events occur in your account.

📚 Full Webhook Guide →

💡 New! Check out our comprehensive webhook documentation with integration examples, troubleshooting guides, and best practices. Read the full guide →

What are Webhooks?

Webhooks are HTTP callbacks that notify your server when specific events happen. Instead of constantly polling the API for changes, webhooks push data to your server in real-time when events occur.

Benefits:

  • • Real-time event notifications
  • • No need to poll the API repeatedly
  • • Integrate license events into your own systems
  • • Automate workflows based on license activity

How Webhooks Work

  1. 1
    Register Your Webhook: Provide a URL where you want to receive notifications. This must be a publicly accessible HTTPS endpoint.
  2. 2
    Select Events: Choose which events to subscribe to (e.g., license.validated, license.activated).
  3. 3
    Receive Events: When events occur, we send a POST request to your URL with event details and a signature for verification.
  4. 4
    Verify & Process: Verify the webhook signature using your secret, then process the event in your application.

Available Events

EventWhen It Fires
license.validatedEvery time a license is successfully validated
license.activatedWhen a new device activates a license for the first time
license.expiredWhen a license reaches its expiration date
license.limit_reachedWhen a license reaches its maximum activations

Webhook Security (Signature Verification)

Every webhook request includes an x-webhook-signature header containing an HMAC-SHA256 signature. Always verify this signature to ensure the webhook came from our servers.

// Node.js example
const crypto = require('crypto');

function verifyWebhook(payload, signature, secret) {
  const hmac = crypto.createHmac('sha256', secret);
  const digest = hmac.update(payload).digest('hex');
  return digest === signature;
}

// In your webhook endpoint
app.post('/webhook', (req, res) => {
  const signature = req.headers['x-webhook-signature'];
  const payload = JSON.stringify(req.body);

  if (!verifyWebhook(payload, signature, YOUR_WEBHOOK_SECRET)) {
    return res.status(401).send('Invalid signature');
  }

  // Process the webhook event
  console.log('Event:', req.body.event);
  console.log('Data:', req.body.data);

  res.status(200).send('OK');
});

Retry Logic

If your webhook endpoint fails to respond or returns an error, we automatically retry with exponential backoff:

  • Attempt 1: Immediate
  • Attempt 2: After 1 minute
  • Attempt 3: After 5 minutes
  • Attempt 4: After 30 minutes

View delivery logs in the Webhooks page to troubleshoot failed deliveries.

Example Webhook Payload

{
  "event": "license.validated",
  "timestamp": "2025-01-02T10:30:00.000Z",
  "data": {
    "licenseKey": "ABCD-1234-EFGH-5678",
    "licenseName": "Production License",
    "fingerprint": "device-abc-123",
    "deviceType": "desktop",
    "ipAddress": "192.168.1.100"
  }
}

Device Management

Track and manage devices that have activated licenses

GET/api/licenses/[id]/devices

Get all devices for a specific license

{
  "devices": [
    {
      "id": "device-id",
      "fingerprint": "unique-fingerprint",
      "deviceName": "John's MacBook",
      "deviceType": "desktop",
      "lastSeenAt": "2025-01-02T10:00:00.000Z",
      "isActive": true
    }
  ],
  "maxActivations": 5,
  "currentActivations": 2
}
PATCH/api/devices/[activationId]

Update device name

// Request
{ "deviceName": "New Device Name" }

// Response
{ "success": true }
DELETE/api/devices/[activationId]

Revoke device access (deactivates the device)

Analytics

Access usage statistics and trends

GET/api/analytics/validations?range=30d

Get validation time series data (30d or 90d)

GET/api/analytics/activations?range=30d

Get activation trends over time

GET/api/analytics/overview?range=30d

Get comprehensive overview including top licenses, success rates, and device distribution

{
  "topLicenses": [
    { "name": "License A", "validations": 1250 }
  ],
  "successRate": 98.5,
  "totalValidations": 5000,
  "deviceDistribution": [
    { "type": "desktop", "count": 150 },
    { "type": "mobile", "count": 75 }
  ]
}

Complete Endpoint Reference

License Validation

POST/api/validatePublic

Validate a license key with device fingerprint

License Management

GET/api/licensesProtected

Get all licenses for current user

POST/api/licensesProtected

Create a new license

POST/api/licenses/bulkProtected

Bulk create licenses or import from CSV

PATCH/api/licensesProtected

Update license (status, customer assignment)

DELETE/api/licenses?id={id}Protected

Delete a license

GET/api/licenses/[id]/logsProtected

Get validation logs for a license

GET/api/licenses/[id]/devicesProtected

Get all devices for a license

Device Management

PATCH/api/devices/[activationId]Protected

Update device name

DELETE/api/devices/[activationId]Protected

Revoke device access

Customer Management

GET/api/customersProtected

Get all customers with license counts

POST/api/customersProtected

Create a new customer

GET/api/customers/[id]Protected

Get customer details with all assigned licenses

PATCH/api/customersProtected

Update customer details

DELETE/api/customers?id={id}Protected

Delete customer (unassigns all licenses)

Webhooks

GET/api/webhooksProtected

Get all webhooks

POST/api/webhooksProtected

Create a new webhook

GET/api/webhooks/[id]/logsProtected

Get webhook delivery logs

POST/api/webhooks/testProtected

Send a test webhook

Products

GET/api/productsProtected

Get all products

POST/api/productsProtected

Create a new product

PATCH/api/products/[id]Protected

Update product details or set as default

DELETE/api/products/[id]Protected

Delete product (cannot delete default product)

Templates

GET/api/templatesProtected

Get all templates

POST/api/templatesProtected

Create a new template

POST/api/templates/[id]/applyProtected

Create licenses from template

Analytics

GET/api/analytics/validationsProtected

Get validation time series data

GET/api/analytics/activationsProtected

Get activation trends

GET/api/analytics/overviewProtected

Get comprehensive analytics overview

Email Preferences

GET/api/email-preferencesProtected

Get email notification preferences

PATCH/api/email-preferencesProtected

Update email notification preferences

Production Recommendations

For production use, consider implementing rate limiting on the validation endpoint to prevent abuse. Use HTTPS for all API requests to ensure data security.