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:
- Prepare the product, its policies and releases.
- Map your old licenses to LicenseManager’s.
- Import them with the API.
- 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:
| Field | From your old license | Notes |
|---|---|---|
email | The customer’s email | Required. The customer is found or created from it, regardless of case. |
key | The license key | Kept as is, up to 255 characters, case sensitive. Must be unique in the product. |
policyId | The offer it was sold as | Defaults to the default policy. |
expiresAt | The expiration date | Always send it, null for never: left out, it’s computed from the policy’s duration from today. |
maxMachines | The number of activations allowed | null for unlimited. Defaults to the policy’s. |
maxOfflineDurationSeconds | Defaults to the policy’s. At least 3600. | |
maxVersion | The 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. |
price | What was paid | Optional, for your revenue stats. |
meta | Anything else | Like { "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
409andkey_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.createdevent 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
metaif 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.