Guides
Migration
Migrate your existing licenses from other platforms to Licentric with zero downtime.
1. Supported Platforms
Licentric supports importing licenses from these platforms via CSV export.
| Platform | Format | Fields Imported |
|---|---|---|
| Keygen | CSV export from Keygen dashboard | License key, policy, user email, status, created date, expiry |
| Cryptlex | CSV export from Cryptlex dashboard | License key, product, user email, status, activation count |
| LemonSqueezy | CSV export from LemonSqueezy dashboard | License key, product, customer email, status, variant |
2. Export from Source Platform
Export your licenses as a CSV file from the source platform's dashboard. Include all fields you want to preserve: keys, customer emails, statuses, and expiration dates.
3. Field Mapping
Licentric auto-maps common field names during import. You can review and adjust the mapping before confirming.
# Example field mapping (Keygen → Licentric)
#
# Source (Keygen) → Target (Licentric)
# ───────────────────── ──────────────────
# license.key → license.key (preserved)
# license.policy.name → policy.name
# license.user.email → customer.email
# license.status → license.status
# license.expiry → license.expiresAt
# license.maxMachines → policy.maxMachines
# license.metadata → license.metadata4. Import via Dashboard
Upload your CSV through the dashboard import wizard. Create matching products and policies first so licenses can be assigned correctly.
# Step 1: Export from source platform
# Download your licenses as CSV from the source dashboard
# Step 2: Prepare your Licentric account
# Create matching products and policies in Licentric first
# Step 3: Import via dashboard
# Dashboard → Settings → Import Data → Upload CSV
# Licentric auto-maps common fields and lets you adjust
# Step 4: Verify imported data — listing is a management-plane read, not
# exposed on the SDK client (Management API key, licenses:read scope).
# Note: the raw license key is only ever returned once, at creation/import
# time — it is never readable back from a list or a get-by-id call.
import httpx
licenses = httpx.get(
"https://www.licentric.com/api/v1/licenses",
headers={"Authorization": "Bearer lk_live_your_key_here"},
params={"limit": 50},
).json()["data"]["data"] # paginated envelope: {"data": {"data": [...], "cursor", "hasMore"}}
for lic in licenses:
print(f"{lic['id']} — {lic['status']} — {lic['userEmail']}")5. Zero-Downtime Migration
For production systems, use a dual-write strategy: validate against both platforms during the migration period, then cut over to Licentric once all licenses are verified.
# Zero-downtime migration strategy
#
# Phase 1: Dual-write (1-2 weeks)
# ─────────────────────────────────
# Keep the old platform active while Licentric mirrors it.
# Your app validates against BOTH platforms.
from licentric import Licentric
licentric_client = Licentric(api_key="lk_live_your_key_here")
def validate_during_migration(license_key: str) -> bool:
"""Validate against both platforms during migration."""
# Try Licentric first (new)
try:
result = licentric_client.validate(key=license_key)
if result.valid:
return True
except Exception:
pass
# Fall back to old platform
return old_platform_validate(license_key)
# Phase 2: Cutover
# ─────────────────
# Once all licenses are migrated and verified:
# 1. Update your app to validate only against Licentric
# 2. Disable the old platform
# 3. Monitor for any missed licenses6. Verify the Migration
After importing, verify that all licenses were migrated correctly by validating each one programmatically.
# Post-migration verification checklist
#
# The raw license key is only ever returned ONCE, at import/creation time —
# it can never be read back from a list or get-by-id call (Licentric stores
# only a hash). So verification validates using the keys YOUR import script
# already captured when it created each license, not keys fetched from the API.
from licentric import Licentric
client = Licentric(api_key="lk_live_your_key_here")
def verify_migration(imported_keys: dict[str, str]):
"""Verify every migrated license validates correctly.
Args:
imported_keys: {license_id: raw_key}, captured by your import script
from each POST /api/v1/licenses response at creation time.
"""
errors = []
for license_id, key in imported_keys.items():
result = client.validate(key=key)
if not result.valid:
errors.append(f"{license_id}: expected valid, got {result.code}")
if errors:
print(f"Migration issues found: {len(errors)}")
for error in errors:
print(f" - {error}")
else:
print("All licenses verified successfully!")Public API
POST /api/v1/migrations/import:issues new Licentric keys and emails each customer the replacement. Use this when you want a clean slate (e.g. rotating keys after a competitor breach, or re-issuing under a new prefix).