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" : "john@example.com"
},
"product" : {
"id" : "prd_abc456" ,
"name" : "Premium Software License" ,
"slug" : "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_activationLicense created but not yet activated activeLicense is activated and valid for use expiredLicense has passed its expiration date revokedLicense 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_pageinteger Number of licenses per page (default 50, max 100) cursorstring Pagination cursor from previous response statusstring Filter by status (pending_activation, active, expired, revoked) customer_idstring Filter by customer public ID (e.g., cus_abc123) product_idstring 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/licensesGET List all licenses with filtering /v1/licenses/{licenseKey}GET Get specific license details /v1/licenses/{licenseKey}/activatePOST Activate license on a device /v1/licenses/{licenseKey}/revokePOST Permanently revoke a license /v1/licenses/{licenseKey}/activationsGET 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
Products Guide Create license-type products
Licenses API View the complete Licenses API reference
Get License Retrieve license details
Activate License Activate on a device