Migrating from LicenseSeat
LicenseSeat is a strong license-only product with native SDKs (Swift, Rust, plus C#/C++/JS). Licensr covers the same validation and seat-activation surface, then adds the payments, branded buy page, and customer portal that LicenseSeat expects you to assemble yourself.
Use this guide if you already ship against LicenseSeat and want to move validation (and optionally checkout) to Licensr.
Concept map
| LicenseSeat | Licensr | Notes |
|---|---|---|
| Product / app | Plugin (plugin_slug) | Fixed at creation; carries activation mode (seat or domain). |
| License key | License key (lic_...) | Same idea — a secret string the end user enters. |
| Activation / node | Activation (seat or domain) | Licensr also supports domain-mode for WordPress/web plugins. |
CheckEntitlement("name") | Plan feature_flags JSON | Returned on every /validate, /activate, and /token response. Gate in-process; no extra round-trip. |
| Signed "machine file" (offline) | EdDSA JWT via POST /v1/license/token | Verify against the per-plugin JWKS. See offline signed tokens. |
| Floating / concurrent seats | Not supported | Licensr uses node-locked seats. Plan seat caps, don't heartbeats. |
| Your Gumroad / Paddle / Stripe | Built-in checkout on your Stripe / Mercado Pago / PayPal | /buy/your-slug + POST /v1/billing/checkout. 0% revenue share. |
See the full side-by-side at licensr.app/vs/licenseseat.
Replace the validate call
LicenseSeat SDKs typically expose something like client.validate(key) / CheckLicense. Against Licensr the same check is one REST call (or one SDK method):
import {LicensrClient} from '@licensr/sdk';
const client = new LicensrClient({
apiKey: 'pk_live_...', // create under Admin → Plugin → API keys
pluginSlug: 'my-plugin',
});
const result = await client.validate({licenseKey: userEnteredKey});
if (result.valid) {
unlockFullFeatures(result.featureFlags);
} else if (result.entitlement === 'limited') {
unlockDegradedMode(); // perpetual-fallback plan
}
Equivalent raw request:
POST /v1/license/validate
Authorization: Bearer pk_live_...
Content-Type: application/json
{"license_key":"lic_...","plugin_slug":"my-plugin"}
Always branch on valid / entitlement, never on HTTP status — an unknown key returns 200 {valid: false}, not 404.
Seats and activations
- On first successful validate (or on an explicit "Activate" UI), call
POST /v1/license/activatewithactivation_type: "seat"and a stable machine identifier. - Pass the same identifier as the SDK
deviceId/X-Device-Idso rate limits bucket per installation. - Let customers free a seat themselves via the branded portal — you rarely need
deactivatein-product.
await client.activate({
licenseKey: userEnteredKey,
activationType: 'seat',
identifier: stableHwid,
label: 'Studio iMac',
});
C++ and C# hosts: see the C++ SDK (licensr::compute_hardware_id) and C# SDK (Unity SystemInfo.deviceUniqueIdentifier, or a persisted GUID).
Entitlements → feature flags
LicenseSeat's named entitlement API becomes a JSON object on the plan:
{
"auto_backup": true,
"export_limit": 100
}
Set it under Admin → Plan → Advanced options. Every validate/activate/token response echoes it as feature_flags. Default gracefully when a flag is missing so older plans keep working.
Offline
- While online:
client.token({licenseKey})(orPOST /v1/license/token). - Persist the JWT (JS:
OfflineTokenStore; C++:FileTokenStore; C#:IOfflineTokenStore). - On next launch, verify locally against the JWKS URL before any network call.
Offline tokens prove issuance + expiry, not live revocation — re-validate online before exp.
What you gain that LicenseSeat doesn't ship
- Hosted buy page at
/buy/your-slugon your own payment account. - Subscription lifecycle (renewals, grace, cancel → license state) without wiring webhooks yourself.
- Branded customer portal for seat and billing self-serve.
- Domain-mode activation + Origin guard for web/WordPress plugins.
Migration checklist
- Create the plugin + plan(s) in Licensr; copy
feature_flagsfrom your LicenseSeat entitlement names. - Issue a
pk_live_...(client-safe scopes) and embed it via the SDK of your host language. - Swap validate/activate calls; keep your existing key-entry UI.
- Optionally cut over checkout to
/buy/your-slugand retire Gumroad/Paddle for new sales. - Re-issue licenses for existing customers (export → bulk import, or a one-time script) — keys are not portable across vendors.
- Keep LicenseSeat running in parallel until the cohort has activated on Licensr at least once.