Skip to content

Validate a key

Validate a license key for a given device. This is the hot path — it is served from Cloudflare’s edge KV cache and returns in under 10ms on cache hits.

Endpoint

POST /v1/validate

Required permission: validate

Request

{
"key": "MYAPP-ABCD-EFGH-IJKL",
"device_fingerprint": "sha256_of_stable_device_id",
"app_version": "1.2.0"
}
FieldTypeRequiredDescription
keystringThe license key string
device_fingerprintstringSHA-256 hash of the device’s stable identifier (machine ID, hardware ID, etc.)
app_versionstringYour app’s version string — stored for analytics

Response — valid key

{
"valid": true,
"plan": "pro",
"expires_at": "2027-08-16T12:00:00Z",
"activations_used": 1,
"activation_limit": 3
}
FieldTypeDescription
validbooleanWhether the key is valid for this device
planstring | nullThe plan tier this key grants
expires_atstring | nullISO 8601 expiry; null for perpetual licenses
activations_usedintegerNumber of unique devices currently activated
activation_limitintegerMaximum concurrent activations allowed

Response — invalid key

{
"valid": false,
"reason": "revoked"
}
ReasonDescription
not_foundKey does not exist in this account
revokedKey has been revoked
expiredKey has passed its expires_at date
activation_limitKey has reached its activation limit on other devices

Caching behavior

Lizen caches validation responses in Cloudflare KV with a 60-second TTL. On cache hits, the request never reaches the origin — latency is under 1ms at the nearest PoP.

Cache is invalidated immediately on revocation. After revoking a key, all subsequent validate calls return valid: false within milliseconds.

Example

import { Lizen } from '@lizen/sdk';
const lizen = new Lizen({ apiKey: process.env.LIZEN_API_KEY! });
const result = await lizen.validate({
key: storedLicenseKey,
deviceFingerprint: getMachineId(),
});
if (!result.valid) {
// result.reason: 'not_found' | 'revoked' | 'expired' | 'activation_limit'
showLicenseError(result.reason);
app.quit();
}

Rate limits

PlanCalls/day
Free500
Hobby10,000
Starter50,000
Growth200,000
EnterpriseUnlimited

Exceeded rate limits return 429 with a retry_after value in seconds.