Guides
Free Trials
Offer time-limited trial licenses that automatically expire and convert to paid plans.
Template used
This guide uses the
trial policy template: 1 device, 14 days, no offline access, isTrial: true.1. Issue a Trial License
When a new user signs up, issue a trial license automatically. The trial policy template limits usage to one device for 14 days with no offline access.
Python
create_trial.py
# Licenses are a management-plane resource, not exposed on the SDK client
# — create them via the REST API (Management API key, licenses:write scope).
import httpx
api_key = "lk_live_your_key_here"
headers = {"Authorization": f"Bearer {api_key}"}
trial_license = httpx.post(
"https://www.licentric.com/api/v1/licenses",
headers=headers,
json={
"productId": "YOUR_PRODUCT_ID",
"policyId": "YOUR_TRIAL_POLICY_ID",
"userEmail": "[email protected]",
"metadata": {"source": "signup_form"},
},
).json()["data"]
# The trial policy template sets:
# maxMachines=1, durationDays=14,
# isTrial=true, offlineAllowed=falseTypeScript
create-trial.ts
const trialLicense = (
await (
await fetch("https://www.licentric.com/api/v1/licenses", {
method: "POST",
headers: {
Authorization: `Bearer ${apiKey}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
productId: "YOUR_PRODUCT_ID",
policyId: "YOUR_TRIAL_POLICY_ID",
userEmail: "[email protected]",
metadata: { source: "signup_form" },
}),
})
).json()
).data;2. Automatic Expiration
Trial licenses expire automatically after the configured duration (14 days by default). No cron jobs or manual intervention required. When a trial expires, validation returns the EXPIRED code.
3. Check Trial Status
Show users how many days remain in their trial and prompt them to upgrade before it expires.
Python
check_trial.py
from datetime import datetime, timezone
def check_trial_status(license_key: str):
"""Check if a license is a trial and show days remaining."""
result = client.validate(key=license_key)
if not result.valid:
if result.code == "EXPIRED":
print("Your trial has expired. Upgrade to continue.")
show_upgrade_prompt()
return False
print(f"License invalid: {result.code}")
return False
# Check trial metadata (get_license needs the Management API key, not the
# license key — it's a separate authenticated call)
if not result.license:
return True
license = client.get_license(result.license.id)
if license.policy.is_trial and license.expires_at:
expires_at = datetime.fromisoformat(license.expires_at)
days_left = (expires_at - datetime.now(timezone.utc)).days
print(f"Trial: {days_left} days remaining")
return TrueTypeScript
check-trial.ts
async function checkTrialStatus(licenseKey: string) {
const result = await client.validate({ key: licenseKey });
if (!result.valid) {
if (result.code === "EXPIRED") {
showUpgradePrompt();
return false;
}
return false;
}
// getLicense needs the Management API key, not the license key — it's a
// separate authenticated call, typically made from your own backend.
if (!result.license) {
return true;
}
const license = await client.getLicense(result.license.id);
if (license.policy?.isTrial && license.expiresAt) {
const daysLeft = getDaysUntil(license.expiresAt);
showTrialBanner(`Trial: ${daysLeft} days remaining`);
}
return true;
}4. Convert Trial to Paid
When a user upgrades, create a new license with the paid policy and revoke the trial. This cleanly separates trial and paid entitlements.
convert.py
def convert_trial_to_paid(
trial_license_email: str,
paid_product_id: str,
paid_policy_id: str,
trial_license_id: str
):
"""Convert a trial license to a paid license.
There is no "change this license's policy" operation — policyId is fixed
at creation. The supported path is: create a new paid license, then
revoke the trial.
"""
paid_license = httpx.post(
"https://www.licentric.com/api/v1/licenses",
headers=headers,
json={
"productId": paid_product_id,
"policyId": paid_policy_id,
"userEmail": trial_license_email,
},
).json()["data"]
# Revoke the trial
httpx.post(
f"https://www.licentric.com/api/v1/licenses/{trial_license_id}/revoke",
headers=headers,
)
return paid_licenseStripe integration
Combine trials with Stripe Checkout for a seamless trial-to-paid conversion. When the Stripe subscription activates, Licentric automatically provisions the paid license and revokes the trial.
Trial abuse prevention
The trial template limits licenses to 1 device with fingerprinting enabled. This prevents the same machine from obtaining multiple trial licenses. For stricter enforcement, set fingerprint uniqueness to
PER_ACCOUNT.