Documentation
Integrate license validation into your software. REST API reference and integration guide.
- Sign up at Licentra and create an app in the dashboard
- Go to your app → Credentials tab → generate an API secret
- Create licenses for your app (single or batch)
- Call the validate endpoint from your software
The validate API is a single POST endpoint. No SDK required. Use your app ID and API secret for authentication.
POST https://your-domain.com/api/licenses/validate
Content-Type: application/json
Request body
| Field | Type | Required | Description |
|---|---|---|---|
| appId | string | yes | Your app ID |
| apiSecret | string | yes | API secret from App → Credentials |
| licenseKey | string | yes | The license key to validate |
| hwid | string | no | Device identifier. Required when license has HWID lock enabled. |
Success response (200)
Valid license returns:
{
"success": true,
"data": {
"valid": true,
"license": {
"id": "...",
"key": "XXXXX-XXXX",
"note": "",
"status": "active",
"expiryDate": null,
"hwidLocked": false,
"hwidLimit": 5,
"hwids": [],
"createdAt": "...",
"updatedAt": "..."
}
}
}Invalid license (200)
Invalid licenses still return 200 with valid: false and a reason code.
{
"success": true,
"data": {
"valid": false,
"reason": "license_not_found"
}
}Reason codes
| reason | Meaning |
|---|---|
| app_not_found | Invalid app ID or app does not exist |
| license_not_found | No license with that key for this app |
| license_not_active | License is suspended |
| license_expired | Expiry date has passed |
| hwid_required | License has HWID lock but no hwid was sent |
| hwid_mismatch | HWID not in the allowed list for this license |
| hwid_limit_reached | Device limit reached, cannot add new HWID |
Error responses
| Status | When |
|---|---|
| 400 | Missing appId, apiSecret or licenseKey |
| 401 | Invalid API secret (invalid credentials) |
| 403 | App suspended |
| 429 | Rate limit exceeded (IP, per-license, or per-app) |
| 429 | Plan quota exceeded for the month (app auto-suspended) |
When a license has HWID lock enabled, you must send the device identifier (hwid) on every validation. Licentra stores up to the configured limit (1–5 devices per license).
Generating a stable HWID
- Use a stable identifier from your platform (e.g. machine-id, CPU serial, MAC hash)
- Max length: 256 characters
- IP: 100 requests per minute per IP
- Per license: Configurable per app (1–100 per minute, default 10)
- Per app: Plan based (see Plan quotas below)
When a license exceeds its per-minute limit, 429 is returned. Licenses with 50+ blocked requests in 10 minutes may trigger auto-suspend if enabled in the app settings.
each plan has a monthly validation quota and a per-minute limit per app. when quota is exceeded, the app is suspended until the next month. quota resets monthly. see the pricing page for current limits.
any programming language works. the validate API is a standard REST endpoint, if your language can make HTTP POST requests, you can integrate. we show cURL, Python and JavaScript below, but the same call works from PHP, Go, Rust, C#, Java or anything else.
cURL
curl -X POST https://your-domain.com/api/licenses/validate \
-H "Content-Type: application/json" \
-d '{
"appId": "YOUR_APP_ID",
"apiSecret": "YOUR_API_SECRET",
"licenseKey": "XXXXX-XXXX",
"hwid": "optional-device-hash"
}'Python
import requests
def validate_license(license_key: str, hwid: str = None):
url = "https://your-domain.com/api/licenses/validate"
payload = {
"appId": "YOUR_APP_ID",
"apiSecret": "YOUR_API_SECRET",
"licenseKey": license_key,
}
if hwid:
payload["hwid"] = hwid
resp = requests.post(url, json=payload, timeout=10)
resp.raise_for_status()
return resp.json()
result = validate_license("XXXXX-XXXX")
if result.get("data", {}).get("valid"):
print("License valid")
else:
print("Invalid:", result.get("data", {}).get("reason"))JavaScript (Node.js)
async function validateLicense(licenseKey, hwid = null) {
const res = await fetch(`https://your-domain.com/api/licenses/validate`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
appId: 'YOUR_APP_ID',
apiSecret: 'YOUR_API_SECRET',
licenseKey,
...(hwid && { hwid }),
}),
});
const data = await res.json();
if (!res.ok) throw new Error(data.message || 'validation failed');
return data;
}
const result = await validateLicense('XXXXX-XXXX');
if (result.data?.valid) {
console.log('License valid');
} else {
console.log('Invalid:', result.data?.reason);
}Reach out at licentra.support@gmail.com. We respond within 24–48 hours on business days.