Chariow provides built-in license key management for software products. Licenses are automatically generated when customers purchase license-type products and can be activated, validated, and revoked through the API.
License Object
A license contains comprehensive information about its status, activation history, and validity:
{
"id": "lic_abc123",
"status": "active",
"customer": {
"id": "cus_xyz789",
"name": "John Doe",
"email": "[email protected]"
},
"product": {
"id": "prd_abc456",
"name": "Premium Software License"
},
"license": {
"key": "ABC-123-XYZ-789",
"masked_key": "ABC-***-***-789"
},
"is_active": true,
"is_expired": false,
"can_activate": true,
"activations": {
"count": 3,
"max": 10,
"remaining": 7
},
"certificate_url": "https://api.chariow.com/certificates/lic_abc123.pdf",
"metadata": null,
"activated_at": "2025-01-15T10:30:00.000000Z",
"expires_at": "2026-01-15T10:30:00.000000Z",
"expired_at": null,
"revoked_at": null,
"created_at": "2025-01-15T09:00:00.000000Z",
"updated_at": "2025-01-15T10:30:00.000000Z"
}
Key Fields
license.key: The unique license key string (e.g., ABC-123-XYZ-789)
license.masked_key: Masked version for display (e.g., ABC-***-***-789)
status: Current license status (see table below)
is_active: Boolean indicating if the license is currently active and usable
is_expired: Boolean indicating if the license has expired
can_activate: Boolean indicating if the license can be activated (has remaining slots)
activations.count: Current number of device activations
activations.max: Maximum allowed activations
activations.remaining: Number of activation slots remaining
certificate_url: URL to download the license certificate (if available)
activated_at: When the license was first activated (null if never activated)
expires_at: When the license will expire (null for lifetime licenses)
revoked_at: When the license was revoked (null if not revoked)
License Statuses
| Status | Description |
|---|
pending_activation | License created but not yet activated |
active | License is activated and valid for use |
expired | License has passed its expiration date |
revoked | License has been permanently revoked |
Listing Licenses
Retrieve all issued licenses for your store:
curl -X GET "https://api.chariow.com/v1/licenses" \
-H "Authorization: Bearer sk_live_your_api_key"
Query Parameters
| Parameter | Type | Description |
|---|
per_page | integer | Number of licenses per page (default 50, max 100) |
cursor | string | Pagination cursor from previous response |
status | string | Filter by status (pending_activation, active, expired, revoked) |
customer_id | string | Filter by customer public ID (e.g., cus_abc123) |
product_id | string | Filter by product public ID (e.g., prd_def456) |
Filtering Examples
# Get active licenses only
curl -X GET "https://api.chariow.com/v1/licenses?status=active" \
-H "Authorization: Bearer sk_live_your_api_key"
# Get licenses for a specific product
curl -X GET "https://api.chariow.com/v1/licenses?product_id=prd_abc123" \
-H "Authorization: Bearer sk_live_your_api_key"
# Get licenses for a specific customer
curl -X GET "https://api.chariow.com/v1/licenses?customer_id=cus_xyz789" \
-H "Authorization: Bearer sk_live_your_api_key"
Getting a License by Key
Retrieve a specific license using its license key:
curl -X GET "https://api.chariow.com/v1/licenses/ABC-123-XYZ-789" \
-H "Authorization: Bearer sk_live_your_api_key"
Validating a License
To validate a license in your application, retrieve it and check the status:
async function validateLicense(licenseKey) {
const response = await fetch(
`https://api.chariow.com/v1/licenses/${licenseKey}`,
{ headers: { 'Authorization': 'Bearer sk_live_your_api_key' }}
);
if (!response.ok) {
return { valid: false, reason: 'License not found' };
}
const { data } = await response.json();
if (!data.is_active) {
return { valid: false, reason: 'License is not active' };
}
if (data.is_expired) {
return { valid: false, reason: 'License has expired' };
}
return { valid: true, license: data };
}
Activating a License
Activate a license on a device. The system automatically captures IP address and user agent:
curl -X POST "https://api.chariow.com/v1/licenses/ABC-123-XYZ-789/activate" \
-H "Authorization: Bearer sk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"device_identifier": "00:1B:44:11:3A:B7"
}'
First Activation Behaviour
On the first activation:
- Status changes from
pending_activation to active
activated_at timestamp is set
expires_at is calculated based on product validity period
activation_count increments to 1
Subsequent Activations
On additional activations:
activation_count is incremented
- A new activation record is created
- License status remains
active
Activation Limits
Each license has a maximum number of activations (max_activations). When the limit is reached, further activations will fail:
{
"message": "Activation limit reached",
"data": [],
"errors": []
}
Check can_activate and activations_remaining before attempting activation.
Revoking a License
Revoke a license to prevent further use:
curl -X POST "https://api.chariow.com/v1/licenses/ABC-123-XYZ-789/revoke" \
-H "Authorization: Bearer sk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"reason": "Customer requested refund"
}'
Revoking a license is permanent. The license cannot be reactivated after revocation.
Getting Activation History
View all activations for a specific license with detailed device tracking:
curl -X GET "https://api.chariow.com/v1/licenses/ABC-123-XYZ-789/activations?per_page=20" \
-H "Authorization: Bearer sk_live_your_api_key"
Response
{
"data": [
{
"id": "act_abc123",
"activated_by": {
"ip": {
"value": "203.0.113.45",
"country": {
"code": "US",
"name": "United States"
}
},
"user_agent": {
"browser": "Chrome",
"platform": "Windows",
"device": "desktop"
},
"device": "00:1B:44:11:3A:B7"
},
"metadata": null,
"activated_at": "2025-01-18T15:42:00.000000Z",
"created_at": "2025-01-18T15:42:00.000000Z"
},
{
"id": "act_def456",
"activated_by": {
"ip": {
"value": "198.51.100.12",
"country": {
"code": "FR",
"name": "France"
}
},
"user_agent": {
"browser": "Safari",
"platform": "macOS",
"device": "desktop"
},
"device": "A4:5E:60:D8:2F:11"
},
"metadata": null,
"activated_at": "2025-01-16T09:15:00.000000Z",
"created_at": "2025-01-16T09:15:00.000000Z"
}
],
"pagination": {
"count": 2,
"per_page": 20,
"next_cursor": null,
"prev_cursor": null,
"has_more_pages": false
}
}
What’s Tracked
Each activation record contains:
- IP Address: Automatically captured from the activation request, with geolocation
- User Agent: Parsed browser and platform information
- Device Identifier: Optional identifier you provide (MAC address, UUID, etc.)
- Timestamp: When the activation occurred
- Metadata: Optional custom data
This is useful for:
- Auditing license usage
- Detecting suspicious activity
- Providing customers with device management
- Debugging activation issues
Implementation Example
Here’s a complete example of license validation in a desktop application:
class LicenseManager {
constructor(apiKey) {
this.apiKey = apiKey;
this.baseUrl = 'https://api.chariow.com/v1';
}
async validate(licenseKey) {
const response = await fetch(
`${this.baseUrl}/licenses/${licenseKey}`,
{ headers: { 'Authorization': `Bearer ${this.apiKey}` }}
);
if (!response.ok) {
throw new Error('Invalid license key');
}
const { data } = await response.json();
if (!data.can_activate) {
throw new Error('License cannot be activated');
}
return data;
}
async activate(licenseKey, deviceId) {
const response = await fetch(
`${this.baseUrl}/licenses/${licenseKey}/activate`,
{
method: 'POST',
headers: {
'Authorization': `Bearer ${this.apiKey}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ device_identifier: deviceId })
}
);
if (!response.ok) {
const error = await response.json();
throw new Error(error.message);
}
return response.json();
}
}
// Usage
const manager = new LicenseManager('sk_live_your_api_key');
try {
const license = await manager.validate('ABC-123-XYZ-789');
console.log('License valid:', license.is_active);
await manager.activate('ABC-123-XYZ-789', getDeviceId());
console.log('License activated successfully');
} catch (error) {
console.error('License error:', error.message);
}
API Endpoints Summary
| Endpoint | Method | Description |
|---|
/v1/licenses | GET | List all licenses with filtering |
/v1/licenses/{licenseKey} | GET | Get specific license details |
/v1/licenses/{licenseKey}/activate | POST | Activate license on a device |
/v1/licenses/{licenseKey}/revoke | POST | Permanently revoke a license |
/v1/licenses/{licenseKey}/activations | GET | Get activation history |
Best Practices
Security
- Never expose your API key in client-side code
- Use API keys server-side only
- Validate licenses server-side before granting access
- Store license keys securely on the customer’s device
Device Identification
- Use unique, persistent device identifiers (MAC address, hardware UUID)
- Don’t use user-changeable identifiers (computer name, username)
- Consider platform-specific identifiers (Windows: machine GUID, macOS: hardware UUID)
Activation Management
- Check
can_activate before attempting activation
- Display
activations_remaining to users
- Implement device management UI for customers
- Handle activation errors gracefully
Validation Frequency
- Validate on application startup
- Re-validate periodically (e.g., every 24 hours)
- Cache validation results locally
- Implement offline grace period
Error Handling
- Handle network errors gracefully
- Provide clear error messages to users
- Implement retry logic with exponential backoff
- Log activation attempts for debugging