Skip to main content

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
from licentric import Licentric

client = Licentric(api_key="lk_live_your_key_here")

# Create a trial license for a new user
trial_license = client.licenses.create(
    policy_id="YOUR_TRIAL_POLICY_ID",
    email="prospect@example.com",
    metadata={"source": "signup_form"}
)

# The trial policy template sets:
#   maxMachines=1, durationDays=14,
#   isTrial=true, offlineAllowed=false

TypeScript

create-trial.ts
import { Licentric } from "@licentric/sdk";

const client = new Licentric({ apiKey: "lk_live_your_key_here" });

const trialLicense = await client.licenses.create({
  policyId: "YOUR_TRIAL_POLICY_ID",
  email: "prospect@example.com",
  metadata: { source: "signup_form" },
});

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
def check_trial_status(license_key: str):
    """Check if a license is a trial and show days remaining."""
    result = client.validate(
        key=license_key,
        fingerprint=client.fingerprint()
    )

    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
    license = client.licenses.retrieve(result.license_id)
    if license.policy.is_trial:
        days_left = (license.expires_at - now()).days
        print(f"Trial: {days_left} days remaining")

    return True

TypeScript

check-trial.ts
async function checkTrialStatus(licenseKey: string) {
  const result = await client.validate({
    key: licenseKey,
    fingerprint: client.fingerprint(),
  });

  if (!result.valid) {
    if (result.code === "EXPIRED") {
      showUpgradePrompt();
      return false;
    }
    return false;
  }

  const license = await client.licenses.retrieve(result.licenseId);
  if (license.policy.isTrial) {
    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_id: str,
    paid_policy_id: str
):
    """Convert a trial license to a paid license."""
    # Option 1: Create a new paid license (recommended)
    paid_license = client.licenses.create(
        policy_id=paid_policy_id,
        email=trial_license.email
    )

    # Revoke the trial
    client.licenses.revoke(trial_license_id)

    return paid_license

    # Option 2: Update the policy on the existing license
    # client.licenses.update(
    #     trial_license_id,
    #     policy_id=paid_policy_id
    # )
Stripe 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.