Skip to content

Product License Activation

LaunchKit Pro includes an optional product license key foundation for buyers who sell templates, self-hosted kits, or SaaS products and want activation flows without wiring Payhip, Gumroad, or Lemon Squeezy on day one.

Overview

TopicDefault behavior
EnforcementDisabled (LICENSE_ENFORCEMENT_ENABLED=false)
ProviderMOCK — admin-generated keys only
App accessWorks without activation
Full license keyShown once when admin creates a key
Stored in databaseSHA-256 hash + preview (LKP-****-****-****-ABCD)

When enforcement is disabled, users can still activate keys for testing. The dashboard shows “License enforcement disabled” or “Optional license foundation” messaging.

Environment variables

Add to backend .env (see .env.example):

env
LICENSE_ENFORCEMENT_ENABLED=false
LICENSE_PROVIDER=MOCK
LICENSE_KEY_PREFIX=LKP
LICENSE_MAX_ACTIVATIONS_DEFAULT=3
LICENSE_ALLOW_OFFLINE_MODE=true
LICENSE_SUPPORT_EMAIL=support@launchkitlabs.com
VariablePurpose
LICENSE_ENFORCEMENT_ENABLEDWhen false, the app never blocks access for missing licenses
LICENSE_PROVIDERMOCK today; extend for Payhip/Gumroad/Lemon Squeezy later
LICENSE_KEY_PREFIXPrefix for generated keys (default LKP)
LICENSE_MAX_ACTIVATIONS_DEFAULTDefault seat/instance limit for new keys
LICENSE_ALLOW_OFFLINE_MODEReserved for future offline verification flows
LICENSE_SUPPORT_EMAILShown in buyer-customizable support messaging

License key format

Keys are generated as:

text
LKP-XXXX-XXXX-XXXX-XXXX

Characters exclude easily confused 0/O and 1/I. The full key is hashed before storage; only a preview is retained for UI and audit logs.

Important:

  • License keys must be generated by an admin (or imported through a future marketplace provider integration).
  • A manually typed key with the correct format is still invalid unless it exists in the database.
  • The admin list shows previews only — never full keys after creation.
  • Full keys are shown once immediately after admin creation.
  • Duplicate key hashes are prevented by a unique database constraint on keyHash.

Validation messages

SituationMessage
Bad formatInvalid license key format. Expected format: LKP-XXXX-XXXX-XXXX-XXXX.
Valid format, not in DBLicense key not found. Please use a key generated by the admin license system.
RevokedLicense key is revoked.
ExpiredLicense key is expired.
Activation limitActivation limit reached.
Same instance re-activateIdempotent — does not increment activation count again

Input is normalized before validation: trimmed, uppercased, whitespace/newlines removed, and hyphens standardized when safe.

Editions

Each license maps to a product edition:

Edition keyDisplay name
LITELite Edition
PROPro Edition
ENTERPRISEEnterprise Edition

On activation, workspace settings.license records the edition. Billing subscription edition still takes precedence in the UI when both billing and license exist — mock checkout behavior is unchanged.

User flows

Buyer / workspace user

Dashboard → License (/dashboard/license):

  • View current status, edition, preview, enforcement flag
  • Activate, verify, or deactivate a key
  • Friendly errors for invalid, revoked, expired, or limit-reached keys

Settings also shows a summary card linking to the license page.

Admin

Admin → Licenses (/admin/licenses):

  • Paginated list of all license keys (newest first, previews only)
  • Create keys (full key returned once in a separate success panel — list is refreshed, not replaced)
  • Filter by status, edition, source
  • View activations
  • Revoke keys
  • Duplicate rows are deduplicated client-side; duplicate key hashes are blocked server-side

Demo users can view and try activation where allowed, but cannot create or revoke admin licenses (demo guard).

API endpoints

Authenticated user

MethodPathDescription
GET/license/status?workspaceId=Current license status
POST/license/activateActivate a key
POST/license/verify?workspaceId=Re-check active license
POST/license/deactivate?workspaceId=Deactivate current activation

Admin

MethodPathDescription
GET/admin/licensesPaginated list
POST/admin/licensesCreate key (full key once)
GET/admin/licenses/:licenseIdKey details
PATCH/admin/licenses/:licenseIdUpdate status, edition, limits, expiry
POST/admin/licenses/:licenseId/revokeRevoke key
GET/admin/licenses/:licenseId/activationsList activations

Permissions: admin.licenses.view, admin.licenses.manage.

Audit events

Audit logs record (never the full key):

  • license.created
  • license.updated
  • license.activated
  • license.verified
  • license.deactivated
  • license.revoked
  • license.activation_failed

Customization for buyers

This module is a foundation:

  1. Set LICENSE_ENFORCEMENT_ENABLED=true when you are ready to gate features.
  2. Swap LICENSE_PROVIDER and add provider adapters alongside the mock service.
  3. Connect marketplace webhooks to auto-create keys with source=PAYHIP / GUMROAD / LEMON_SQUEEZY.
  4. Adjust edition mapping or workspace settings merge logic in LicenseService.

Update access (optional)

When you enable license enforcement later, the Product Updates page (/dashboard/updates) can reflect whether update access requires an active license. With enforcement disabled (default), update status and changelog remain available as an optional foundation.

Configure installed version with LAUNCHKIT_VERSION and connect secure downloads through UPDATE_PROVIDER when ready. See Product Updates.

Manual test checklist

  1. Admin creates a Pro license → full key shown once.
  2. User activates → status active, preview only in UI.
  3. Verify and deactivate work.
  4. Admin revoke → user verify shows revoked.
  5. Invalid key → friendly error.
  6. Activation limit enforced when max seats reached.
  7. Demo user blocked from admin license creation.
  8. Billing, AI, dashboard, and settings pages still work with enforcement off.

LaunchKit Pro by LaunchKit Labs — buyer documentation. No secrets in this site.