API Reference
The License Manager provides two API sets: External API for client applications and Internal API for admin operations.
Authentication
All API requests require authentication via API keys.
API Key Types
| Type | Purpose | Header |
|---|---|---|
| External | Client applications | X-API-KEY |
| Internal | Admin/backend operations | X-API-KEY |
Creating API Keys
- Go to License Manager → Settings → API Keys
- Click Create
- Select type (Internal/External)
- Set expiration (optional)
- Save and copy the key
Request Headers
X-API-KEY: your-api-key
X-API-URL: https://client-domain.com
X-API-IP: 192.168.1.100
X-API-LANGUAGE: en
Content-Type: application/json
Accept: application/jsonLegacy Header Support
For backward compatibility with LicenseBox, these legacy headers are also supported:
| Modern Header | Legacy Header |
|---|---|
X-API-KEY | LB-API-KEY |
X-API-URL | LB-URL |
X-API-IP | LB-IP |
X-API-LANGUAGE | LB-LANG |
TIP
Legacy headers work with both new and legacy API endpoints. Useful during migration.
External API
Base URL: /api/external
Used by client applications for license operations.
Connection Check
Verify API connectivity.
GET /api/external/connection-checkResponse:
{
"status": true,
"message": "Connection successful"
}Health Check
Simple health check endpoint (no authentication required).
GET /api/health-checkResponse:
{
"status": "ok"
}Activate License
Activate a license on a domain/IP.
POST /api/external/license/activateHeaders:
X-API-KEY: external-key
X-API-URL: https://client-site.com
X-API-IP: 192.168.1.100Body:
{
"product_id": "PROD-001",
"license_code": "LICENSE-CODE-HERE",
"client_name": "Customer Name",
"verify_type": "non_envato"
}| Field | Description | Required |
|---|---|---|
product_id | Product reference ID | Yes |
license_code | License code to activate | Yes |
client_name | Customer/buyer name | No |
verify_type | non_envato or envato | No |
Response (Success):
{
"is_active": true,
"message": "Activated.",
"lic_response": "<encrypted-license-data>",
"data": {
"license_data": "<encrypted-license-data>"
}
}Response (Error):
{
"is_active": false,
"message": "Your license code is invalid.",
"lic_response": null,
"data": null
}TIP
The lic_response and data.license_data contain encrypted activation data that should be stored locally by the client for subsequent verify/deactivate calls.
Verify License
Check if a license is valid for current domain/IP.
POST /api/external/license/verifyBody:
{
"product_id": "PROD-001",
"license_data": "<encrypted-license-data>",
"client_name": "Customer Name"
}| Field | Description | Required |
|---|---|---|
product_id | Product reference ID | Yes |
license_data | Encrypted data from activation (or license_file for legacy) | Yes |
client_name | Customer/buyer name | No |
Response (Valid):
{
"is_active": true,
"message": "Verified.",
"data": null
}Response (Invalid):
{
"is_active": false,
"message": "License is invalid or not assigned to you.",
"data": null
}Deactivate License
Remove activation from current domain/IP.
POST /api/external/license/deactivateBody:
{
"product_id": "PROD-001",
"license_data": "<encrypted-license-data>",
"client_name": "Customer Name"
}| Field | Description | Required |
|---|---|---|
product_id | Product reference ID | Yes |
license_data | Encrypted data from activation (or license_file for legacy) | Yes |
client_name | Customer/buyer name | No |
Response (Success):
{
"is_active": true,
"message": "Deactivated."
}Response (Error):
{
"is_active": false,
"message": "License is invalid or not assigned to you."
}Check License
Check license status without activating.
POST /api/external/license/checkBody:
{
"license_code": "LICENSE-CODE-HERE"
}Check for Updates
Get available updates for a product.
POST /api/external/update/checkBody:
{
"product_id": "PROD-001",
"current_version": "1.0.0"
}Response (Update Available):
{
"is_active": true,
"message": "A new update is available.",
"update_available": true,
"version": "1.2.0",
"released_at": "2024-01-15",
"summary": "New features and improvements",
"changelog": "<ul><li>Feature A</li><li>Bug fix B</li></ul>",
"update_id": "v1.2.0",
"has_sql": false
}Response (No Update):
{
"is_active": true,
"message": "You are using the latest version.",
"update_available": false,
"version": null
}Get Latest Version
Get latest version info.
POST /api/external/update/latestBody:
{
"product_id": "PROD-001"
}Response:
{
"data": {
"version": "1.2.0",
"released_at": "2024-01-15",
"summary": "New features",
"changelog": "...",
"update_id": "v1.2.0",
"has_sql": false
}
}Download Update
Download update file.
POST /api/external/update/{version}/download/{type}Parameters:
version: Version ID to downloadtype:mainorsql
Body:
{
"product_id": "PROD-001",
"license_data": "<encrypted-license-data>"
}TIP
Returns the file as a binary download stream.
Get Download Size
Get file size before downloading.
GET /api/external/update/{version}/download/{type}/sizeResponse Headers:
Content-Length: 1048576
Content-Type: application/zipInternal API
Base URL: /api/internal
Used for admin/backend operations.
Products
List Products
GET /api/internal/productsGet Product
GET /api/internal/products/{reference_id}Create Product
POST /api/internal/productsBody:
{
"name": "My Product",
"reference_id": "MY-PROD-001",
"envato_id": "12345678",
"description": "Product description",
"license_update": true,
"serve_latest_updates": true,
"is_active": true
}Update Product
PUT /api/internal/products/{reference_id}Activate/Deactivate Product
POST /api/internal/activated-products/{reference_id}
DELETE /api/internal/activated-products/{reference_id}Product Versions
List Versions
GET /api/internal/products/{reference_id}/versionsCreate Version
POST /api/internal/products/{reference_id}/versionsBody:
{
"version_id": "v1.2.0",
"version": "1.2.0",
"summary": "New features release",
"changelog": "<ul><li>Feature A</li><li>Bug fix B</li></ul>",
"released_at": "2024-01-15",
"is_active": true
}Get Version
GET /api/internal/products/{reference_id}/versions/{version_id}Update Version
POST /api/internal/products/{reference_id}/versions/{version_id}Licenses
List Licenses
GET /api/internal/product-licensesQuery Parameters:
search: Search termproduct_reference_id: Filter by productcustomer_id: Filter by customer
Get License
GET /api/internal/product-licenses/{id}Create License
POST /api/internal/product-licensesBody:
{
"product_reference_id": "PROD-001",
"license_code": "LIC-ABC-123",
"type": "perpetual",
"customer_id": "CUST-001",
"email": "[email protected]",
"parallel_uses": 3,
"expires_at": "2025-12-31",
"updates_until": "2025-12-31",
"domains": ["example.com", "*.example.com"],
"ips": ["192.168.1.100"],
"is_valid": true,
"is_envato": false
}Update License
PUT /api/internal/product-licenses/{id}Block/Unblock License
POST /api/internal/blocked-product-licenses/{id}
DELETE /api/internal/blocked-product-licenses/{id}Activations
Create Activation
POST /api/internal/activated-product-activations/{id}Delete Activation
DELETE /api/internal/activated-product-activations/{id}Error Responses
All errors follow this format:
{
"status": false,
"message": "Error description",
"errors": {
"field_name": ["Validation error message"]
}
}Common Error Codes
| HTTP Code | Description |
|---|---|
| 400 | Bad Request - Invalid parameters |
| 401 | Unauthorized - Invalid or missing API key |
| 403 | Forbidden - Insufficient permissions |
| 404 | Not Found - Resource doesn't exist |
| 422 | Validation Error - Invalid input data |
| 429 | Too Many Requests - Rate limit exceeded |
| 500 | Server Error - Internal error |
Rate Limiting
Configure in Settings → API:
- Rate limit period: Number of requests allowed per minute (default: 3000)
- Rate limit method: How to track limits:
ip_address- Limit by client IPapi_key- Limit by API keyapi_key_ip_address- Limit by both (strictest)
Setting: lm_requests_rate_limiting_period (requests per minute)
When exceeded:
{
"status": false,
"message": "Rate limit exceeded. Try again later."
}Encryption
For secure license data transmission:
Encrypted License Format
{
"license_file": "base64-encoded-encrypted-data"
}Decryption
The system supports:
- AES-128-CBC
- AES-256-CBC
- AES-128-GCM
- AES-256-GCM
- Legacy encryption (for migration)
Webhooks
See Webhooks Documentation for event notifications.
SDK Examples
PHP Client
class LicenseClient
{
private string $apiKey;
private string $baseUrl;
public function __construct(string $apiKey, string $baseUrl)
{
$this->apiKey = $apiKey;
$this->baseUrl = $baseUrl;
}
public function activate(string $licenseCode, string $domain): array
{
return $this->request('POST', '/license/activate', [
'license_code' => $licenseCode,
], [
'X-API-URL' => $domain,
'X-API-IP' => $_SERVER['REMOTE_ADDR'] ?? '127.0.0.1',
]);
}
public function verify(string $licenseCode): array
{
return $this->request('POST', '/license/verify', [
'license_code' => $licenseCode,
]);
}
private function request(string $method, string $endpoint, array $data, array $headers = []): array
{
$ch = curl_init($this->baseUrl . '/api/external' . $endpoint);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => $method,
CURLOPT_POSTFIELDS => json_encode($data),
CURLOPT_HTTPHEADER => array_merge([
'Content-Type: application/json',
'Accept: application/json',
'X-API-KEY: ' . $this->apiKey,
], array_map(fn($k, $v) => "$k: $v", array_keys($headers), $headers)),
]);
$response = curl_exec($ch);
curl_close($ch);
return json_decode($response, true);
}
}JavaScript Client
class LicenseClient {
constructor(apiKey, baseUrl) {
this.apiKey = apiKey;
this.baseUrl = baseUrl;
}
async activate(licenseCode, domain) {
return this.request('POST', '/license/activate', {
license_code: licenseCode
}, {
'X-API-URL': domain
});
}
async verify(licenseCode) {
return this.request('POST', '/license/verify', {
license_code: licenseCode
});
}
async request(method, endpoint, data, extraHeaders = {}) {
const response = await fetch(`${this.baseUrl}/api/external${endpoint}`, {
method,
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'X-API-KEY': this.apiKey,
...extraHeaders
},
body: JSON.stringify(data)
});
return response.json();
}
}