Documentation

Integrate license validation into your software. REST API reference and integration guide.

Quick start
get up and running in minutes
  1. Sign up at Licentra and create an app in the dashboard
  2. Go to your app → Credentials tab → generate an API secret
  3. Create licenses for your app (single or batch)
  4. 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.

Validate license
POST to validate a license key

POST https://your-domain.com/api/licenses/validate

Content-Type: application/json

Request body

FieldTypeRequiredDescription
appIdstringyesYour app ID
apiSecretstringyesAPI secret from App → Credentials
licenseKeystringyesThe license key to validate
hwidstringnoDevice identifier. Required when license has HWID lock enabled.

Success response (200)

Valid license returns:

json
{
  "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.

json
{
  "success": true,
  "data": {
    "valid": false,
    "reason": "license_not_found"
  }
}

Reason codes

reasonMeaning
app_not_foundInvalid app ID or app does not exist
license_not_foundNo license with that key for this app
license_not_activeLicense is suspended
license_expiredExpiry date has passed
hwid_requiredLicense has HWID lock but no hwid was sent
hwid_mismatchHWID not in the allowed list for this license
hwid_limit_reachedDevice limit reached, cannot add new HWID

Error responses

StatusWhen
400Missing appId, apiSecret or licenseKey
401Invalid API secret (invalid credentials)
403App suspended
429Rate limit exceeded (IP, per-license, or per-app)
429Plan quota exceeded for the month (app auto-suspended)
Device binding (HWID)
lock licenses to specific devices

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
Rate limits
protect the API from abuse
  • 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.

Plan quotas
monthly validation limits by plan

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.

Code examples
examples in cURL, Python, and JavaScript

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

bash
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

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)

javascript
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);
}
Contact
need help?

Reach out at licentra.support@gmail.com. We respond within 24–48 hours on business days.

Licentra