Skip to Content
GuidesMigrating from another license manager

Migrating from another license manager

Moving to LicenseManager doesn’t mean sending new keys to your customers. With the API, you import each license with its current key, its customer, its expiration and its limits. Then you ship a version of your app that validates keys with LicenseManager, and your customers don’t notice anything.

This guide moves Acme Photo’s 3,000 licenses from another tool. You’ll:

  1. Prepare the product, its policies and releases.
  2. Map your old licenses to LicenseManager’s.
  3. Import them with the API.
  4. Switch your app, and run both tools during the transition.

Do a full import in a test product first, and check the result. Then reset it, or delete it, and import in the live product.

Prepare the product

Create the product

Create the product, and note its id.

Create one policy per offer

One policy per offer you sold: Personal, Business, Lifetime. Each imported license follows one of them for its whole life, and you can’t change it afterwards.

A license’s own settings are set during the import: the policy only gives the defaults, and tells what the license was sold as. Offers you no longer sell still need a policy for their licenses.

Record your past releases

If your licenses include updates for a limited time, create a release for each version you shipped, with its real release date. LicenseManager uses them to know which version each license keeps: a lock date in the past is applied on import, with the latest release by that date.

Import releases before licenses. A license imported with a lock date in the past, before any release is recorded, is cleared without a version: it then allows every version, forever.

Map your licenses

For each old license, prepare the body of a license creation:

FieldFrom your old licenseNotes
emailThe customer’s emailRequired. The customer is found or created from it, regardless of case.
keyThe license keyKept as is, up to 255 characters, case sensitive. Must be unique in the product.
policyIdThe offer it was sold asDefaults to the default policy.
expiresAtThe expiration dateAlways send it, null for never: left out, it’s computed from the policy’s duration from today.
maxMachinesThe number of activations allowednull for unlimited. Defaults to the policy’s.
maxOfflineDurationSecondsDefaults to the policy’s. At least 3600.
maxVersionThe versions it includes{ "version": "2" } for every 2.x version. Or the lock dates, like { "lockMajorAt": "2027-03-01T00:00:00Z", "lockMinorAt": "2027-03-01T00:00:00Z" } for updates until March 1, 2027: computed from the policy from today when left out.
priceWhat was paidOptional, for your revenue stats.
metaAnything elseLike { "legacyId": "lic_8812", "orderId": "A-1042" }, to find the old license again.

Customers’ names can’t be sent with a license. To import them, create each customer first, with POST /v1/products/{productId}/customers and their email and name: their licenses are then added to them.

Import

With an API key, create each license:

curl -X POST https://api.licensemanager.dev/v1/products/x7Kp2QaZ/licenses \ -H "x-api-key: $API_KEY" \ -H "Content-Type: application/json" \ -d '{ "email": "jane@example.com", "key": "ACME-2024-8F3K-29XQ", "policyId": "p4Rt8LmQ", "expiresAt": "2027-03-01T00:00:00Z", "maxMachines": 2, "maxVersion": { "lockMajorAt": "2027-03-01T00:00:00Z", "lockMinorAt": "2027-03-01T00:00:00Z" }, "price": { "amount": 49, "currency": "USD" }, "meta": { "legacyId": "lic_8812" } }'
  • Don’t send sendKey: your customers already have their keys. An import emailing 3,000 customers is the kind of mistake you can’t undo.
  • Make it safe to run again: a license whose key is already imported is refused with 409 and key_taken. Treat it as done, so an interrupted import can start over.
  • Check the result: compare the number of licenses in Licenses with your old tool, and look at a few of them.

Each request counts toward your plan’s API requests: importing 3,000 licenses, with their customers, takes about 6,000. On the Free plan, with 10,000 requests over 30 days, that leaves little for your app’s validations: upgrade before importing a large catalog.

What can’t be imported

  • Machines. Activations of the old tool aren’t imported: each license starts with no machine. Each computer is registered the first time the new version of your app validates its key, and takes a place then. A license allowing 2 machines, used on 2 computers, keeps working on both.
  • History. The old tool’s history isn’t imported. Each license starts with a license.created event dated from the import, by the API key’s name.
  • Creation dates. Licenses are created at the time of the import. Keep the original date in meta if you need it.
  • Last activation. Imported licenses show as Inactive until their key is validated, and don’t count toward your plan’s active licenses until then.

Switch your app

Ship a new version

Ship a version of your app that validates keys with LicenseManager. When it starts with a key activated by the old tool, it validates the same key with LicenseManager once, silently, and stores the new token.

Keep the old tool running

Customers who don’t update keep using the old version, which still talks to the old tool. Keep it running until most of them have updated.

Sell with LicenseManager

Switch your store to create licenses in LicenseManager, like with Stripe, from the day of the import. A license sold in the old tool after the import wouldn’t be in LicenseManager: import it too, or run the import again, which skips the keys already imported.

Edge cases

Keys that differ only by case, like abc-123 and ABC-123, are two different keys. Your new version of the app must send keys exactly as stored: don’t upper-case them, unless your old keys were all upper case.

Keys starting with TEST-. In a live product, the TEST- prefix is removed from the keys you send, as it marks test keys: a live key TEST-8F3K would be imported as 8F3K. In a test product, TEST- is added to every key: your app’s real keys won’t match. Test the import with a copy of your keys, and the switch of your app with test keys.

Two licenses with the same key in your old tool can’t both be imported in one product. Give one of them a new key, and send it to its customer.

Several products. Import each product’s licenses in its own product. A customer of two products is imported as two customers, one per product.

Licenses already expired. Import them with their past expiresAt, to keep their customers, and let them renew: validating their key fails with license_expired.

Email changes. The customer is matched by email: two old licenses of the same person with two emails make two customers. Merge the emails before importing when you can.