Skip to main content

Migrate

Migrate from Keygen to Licentric in under an hour

Four phases — export, prepare, dual-write, cutover — with a symmetrical rollback path back to Keygen if Licentric does not fit. CSV import and the Keygen-API direct import (POST /api/v1/migrations/keygen) both ship today.

Why migrate

Why teams move from Keygen to Licentric

  • You want license keys + Stripe billing in one product with zero webhook glue code.
  • You ship AI agents and need per-agent token budgets, identity, or MCP auth.
  • You want a full admin dashboard on every tier including Free.
  • You're starting in 2026+ and want native container-aware fingerprinting for Docker/K8s.
  • You want a generous free tier (100 active licenses, full API, no credit card).
  • You want a built-in end-user self-service portal on every tier.
  • You want offline files signed with Ed25519 (FIPS 186-5, deterministic, 64-byte signatures).
  • You want compliance scaffolding for the EU AI Act (phased enforcement starting August 2026).

What's preserved

What's preserved across the migration

  • License keys keep their identifiers. Licentric stores both the SHA-256 hash and the raw key (encrypted at rest), so existing keys your customers already hold continue to validate.
  • Machine fingerprints re-validate on first contact. Activated machines from Keygen re-establish their fingerprint binding the next time your app calls validate() against Licentric.
  • Policy → license relationship preserved. The Keygen policy name maps to a Licentric policy with matching maxMachines / expiry / metadata fields.
  • Customer email + status preserved. status=active stays active; suspended stays suspended; revoked remains revoked (terminal-state guarded).
  • Audit history export — you can hold Keygen's audit log as a CSV alongside Licentric's new append-only audit trail. We do not import historical Keygen audit rows into Licentric (separate retention contracts); export them once at cutover and archive.

Procedure

Step-by-step migration procedure

Phase 1: Export from Keygen

Two paths: (a) CSV export from the Keygen dashboard — covers status, key, policy, email; or (b) direct API import which Licentric ships natively. POST /api/v1/migrations/keygen accepts your Keygen account UUID + a Keygen read-only product token, paginates Keygen's https://api.keygen.sh/v1/accounts/{id}/licenses endpoint, and stages every license behind a dryRun flag for verification. Both paths land in the same staging table.

# Direct API import (recommended — no CSV step required):
curl -X POST https://www.licentric.com/api/v1/migrations/keygen \
  -H "Authorization: Bearer lk_live_your_licentric_key" \
  -H "Content-Type: application/json" \
  -d '{
    "keygenAccountId": "00000000-0000-0000-0000-000000000000",
    "keygenApiToken": "prod-XXXXXXXXXXXXXXXXXXXXXXXXX",
    "productId": "your-licentric-product-uuid",
    "policyId": "your-licentric-policy-uuid",
    "dryRun": true
  }'

Phase 2: CSV preparation (field mapping)

If you went with the CSV path, the mapping is mechanical. Licentric's importer auto-maps these columns. The mapping is the same as the in-product migration guide ships — there is one source of truth, and this page links to it.

# Keygen CSV column       →   Licentric field
# ─────────────────────       ──────────────────
# license.key              →   license.key (preserved verbatim)
# 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.metadata (JSON, preserved)

Phase 3: Dual-write window (both systems active)

Keep Keygen serving production while Licentric mirrors it. Your app validates against BOTH platforms — Licentric first, Keygen as fallback. This window is typically 1–2 weeks. The pattern below is taken verbatim from the in-product migration docs (single source of truth) and works for any source platform, not just Keygen.

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,
            fingerprint=licentric_client.fingerprint()
        )
        if result.valid:
            return True
    except Exception:
        pass

    # Fall back to old platform
    return old_platform_validate(license_key)

Phase 4: Cutover

Once every key has been verified in Licentric (the verification snippet in the in-product migration guide enumerates them and re-validates one by one), flip the SDK target. Remove the Keygen fallback branch. Disable the Keygen webhook destinations. Hold the Keygen account in read-only for 30 days as a safety net before final cancellation.

# After cutover, your validation path is simply:
result = client.validate(
    key=license_key,
    fingerprint=client.fingerprint(),
)
if not result.valid:
    raise PermissionError(result.code)

Code diff

Keygen validate() → Licentric validate()

Same operation, different shape. The Licentric snippets below were extracted verbatim from the published SDK source (sdks/python/licentric/client.py and sdks/typescript/src/client.ts); the Keygen snippets reflect the public Keygen REST API convention (application/vnd.api+json, /actions/validate-key).

Python

# BEFORE — Keygen REST API (illustrative; see keygen.sh/docs/api)
import requests
resp = requests.post(
    f"https://api.keygen.sh/v1/accounts/{KEYGEN_ACCOUNT_ID}/licenses/actions/validate-key",
    headers={
        "Content-Type": "application/vnd.api+json",
        "Accept": "application/vnd.api+json",
    },
    json={"meta": {"key": license_key}},
)
data = resp.json()
is_valid = data.get("meta", {}).get("valid", False)

# AFTER — Licentric Python SDK (sdks/python/licentric, verified against client.py)
from licentric import Licentric

client = Licentric(api_key="lk_live_your_key_here")
result = client.validate(
    key=license_key,
    fingerprint=client.fingerprint(),
)
is_valid = result.valid  # ValidationResult with .code, .license, .machine

TypeScript

// BEFORE — Keygen REST API (illustrative; see keygen.sh/docs/api)
const resp = await fetch(
  `https://api.keygen.sh/v1/accounts/${KEYGEN_ACCOUNT_ID}/licenses/actions/validate-key`,
  {
    method: "POST",
    headers: {
      "Content-Type": "application/vnd.api+json",
      "Accept": "application/vnd.api+json",
    },
    body: JSON.stringify({ meta: { key: licenseKey } }),
  },
);
const data = await resp.json();
const isValid = data?.meta?.valid === true;

// AFTER — Licentric TypeScript SDK (sdks/typescript, verified against client.ts)
import { Licentric, fingerprint } from "@licentric/sdk";

const client = new Licentric({ apiKey: "lk_live_your_key_here" });
const result = await client.validate({
  key: licenseKey,
  fingerprint: await fingerprint(),
});
const isValid = result.valid;

Strategy

Dual-write strategy (zero-downtime)

During Phase 3 your application validates against BOTH platforms for 1–2 weeks. Licentric is queried first; on any failure (network, not-found, or invalid), the call falls through to your existing Keygen validation. Customers see zero downtime; you see real production traffic exercising Licentric before cutover.

The dual-write pattern is the same code path that the in-product migration guide ships — a single source of truth so this page never drifts from the canonical sample.

Rollback

Rollback path back to Keygen

The migration is reversible. Licentric supports full data export via the dashboard and the REST API. Both platforms accept standard CSV imports, so a return migration is symmetric to the inbound one. If Licentric does not work out:

  1. Export licenses from Licentric (Dashboard → Settings → Export Data, or GET /api/v1/licenses?limit=200 cursor-paginated).
  2. Re-import the CSV into Keygen using their dashboard's standard license import.
  3. During the 30-day overlap window you left in place at Phase 4, your app's dual-write fallback already validates against Keygen — flip the order (Keygen first, Licentric fallback) for a clean reversal.
  4. Cancel your Licentric subscription via the customer portal. No long-term contract; month-to-month.

Honest

Real-talk: when migration ISN'T worth it

Keep Keygen if any of these describe you. Migration is a real engineering cost and the wrong call if your constraints lean Keygen's way.

  • You need 5+ years of production-stability evidence for procurement. Keygen has 8+ years; Licentric is newer.
  • You require Ruby, Elixir, Swift, .NET, or Java SDKs today. Keygen ships these; Licentric ships Python + TypeScript only (Go in-repo, not yet published).
  • You require SOC 2 Type II compliance evidence today (not at end-of-year). Licentric is pursuing 2026-Q4 and is uncertified today; Keygen Cloud Enterprise is SOC 2 Type II certified.
  • You want fully self-hosted from day 1. Keygen CE is open-source (Fair Source License with an Apache 2.0 conversion clause); Licentric is SaaS only today (self-hosted is on the Year 2 roadmap, gated on 5+ enterprise requests).
  • You have a complex policy hierarchy and prefer Keygen's explicit graph model (Product → Policy → License → Machine → User → Entitlement → Component).
  • You have an existing Keygen integration and the migration cost outweighs the difference.

Founder commitment

Founder-direct migration call — free for the first 50 customers

VISION.md states the operating principle plainly: “Personally onboard first 50 customers. Set up monetization in their codebase on the spot.” If you are evaluating a Keygen-to-Licentric migration, you are in that group.

Book a 30-minute migration call with the founder. We walk through your Keygen schema, run the import in dry-run mode against your real account, identify the dual-write fallback you need on your side, and queue the cutover. No sales pitch — just the work.