Device management
Each key activates on a limited number of devices, and each device holds a seat. Here is how to set that limit, get seats back and choose who may activate.
At a glance
- A device limit
- Up to 1,000; starts at the model's Devices per license
- A device trial
- Takes no seat
- Free unused seats
- Off unless you turn it on; from the model's Offline days to 365 days
- An emailed code
- Lasts 10 minutes and works once
- A shared seat
- A second machine within 30 days; up to 20 counted
Device limits and seats
Each key can be activated on as many devices as its device limit allows, and each activated device holds one seat on the key. The limit starts as:
- the license model's Devices per license, copied onto the key when it is sold; or
-
a limit of the key's own: the
deviceLimitit was issued or imported with, or a Stripe checkout'sdeviceLimitmetadata.
Seat rules:
- Activating again with the fingerprint a seat is keyed by reuses that seat; no second seat is taken.
- A seat counts until it is released, however long ago its device last checked in, unless the license frees unused seats (see Free unused seats).
-
When every seat is taken, a new device's activation is refused with
limit, and adevice.limit_reachedwebhook is sent. - A device trial takes no seat.
Change one key's limit
A key's limit can differ from its model's, for a customer who bought more devices, say. Changing it changes that key alone; the model and its other keys keep theirs.
- From the dashboard: open the key and choose Change beside Devices. When issuing a key, set Devices per license, which starts at the model's; every key of a sale of several gets it.
- From your server: POST /v1/licenses/:key/devices,
or
deviceLimitwhen you issue the key.
Lowering the limit below the devices the key is active on releases none of them:
- They keep working.
-
A new device's activation is refused with
limituntil enough are released that fewer devices than the new limit are active. - The key's Devices row shows more devices than its limit, such as 3 of 2.
- Each change appears in the key's History, and the app's next lease carries the new limit.
Release a seat
- From the app:
deactivate()releases this device's seat and drops the license here. When KeyGrant cannot be reached, it still drops the license and returnsreleased: false, and the seat stays taken until you release it another way. - From the dashboard: open the key, then its Devices tab, and choose Release beside a device, or Release all. Reset devices at the top of the key's page does the same as Release all.
- From your server: DELETE /v1/licenses/:key/activations/:id, with the ID GET /v1/licenses/:key/activations lists.
- From a terminal:
keygrant licenses devicesandfree-device.
After a release:
- Releasing from the dashboard or your server frees the seat at once. A key over a lowered limit may need more than one released (see Change one key's limit).
-
The released device keeps working until its next check-in, which returns
invalidwith reasonrevoked; the app must then be activated again. - Each release sends a
device.releasedwebhook.
Free unused seats
A license model can free the seat of a device that stops checking in, so a customer who wipes or loses a machine never has to ask you for the seat back.
- In the model's settings, turn on Free unused seats and set how many days a device may go without checking in, up to 365.
- It is never fewer days than the model's Offline days: a device can run that long on the lease it holds, so a device that is only offline keeps its seat.
| Where | How to set it |
|---|---|
| The model | Free unused seats. Each key takes the model's days when it is sold, so changing the model changes later keys only. |
| One key | Open it and choose Change beside Unused seats. |
| Issuing a key | Free unused seats after, days, which starts at the model's (empty frees none). |
| Your server | seatReleaseDays when you issue the key, and
POST /v1/licenses/:key/seat-release to change it.
|
When seats are freed:
- KeyGrant frees the seats once a night. The key's Devices tab says, under each device, when its seat will be freed if it does not check in first.
-
The key's History records each one freed, with when the device was last seen, and a
device.releasedwebhook is sent withreason:inactive. - A freed device that checks in again takes a seat back, under the same activation, if the key has one free: the app keeps working with nothing to do.
- If every seat is taken, it is refused as any released device is, and the app must be activated again.
- Your customers see it on their license in the customer portal, as Unused devices.
Sell more devices
A customer can buy more devices for the key they already hold, through Stripe or Paddle, with no second key:
- On a perpetual license model, turn on Sell as an upgrade. The switch appears only while a Stripe or Paddle account is linked, and the model's price is its Stripe or Paddle price.
- Choose Devices under What it upgrades.
- Set Devices it adds: how many one purchase adds, such as 2 for "Two more devices". Buying two at once adds twice as many.
-
Open your Payment Link from the app with
upgradeUrl, so the sale names the key. A link you send one customer can end in?client_reference_id=and their license key.
// From the app: this device's activation id goes on the payment link,// so the sale finds the key it runs on.const url = await license.upgradeUrl('https://buy.stripe.com/...') What a paid checkout does:
- It finds the customer's key as every upgrade does: the key the link names when it can take them, else the one key at the buyer's address that can (see How KeyGrant finds the key).
- It must be a perpetual or timed key of the product, in the checkout's mode, and currently valid.
- A checkout that does not say how many were bought counts as one, and your account's owners are told by email.
- The key keeps its key string, its devices, its versions and its entitlements; only its limit rises, and never past 1,000.
- It never creates a key.
A device sale is held when:
- It finds no key that can take it: neither the key the link named nor any key at the buyer's address.
- The address holds more than one key that can take it, or more than 20 keys that might, and the link named none of them.
- The devices would take the key past 1,000.
- KeyGrant cannot tell its line in the checkout: it was bought with other items, or Stripe would not give the checkout's lines.
A held sale waits for you to attach it to a key or refund it: see Held sales.
- Refunds: a full refund (while Refunds revoke keys is on) or a lost dispute takes the devices back, unless the key's limit has been changed since by anything but a later device sale, and the key keeps working.
- No device is released: a key back under the devices it is on keeps them all, and a new device waits until fewer than its limit are active.
- Emails: while KeyGrant sends your customer mail, it emails the customer that their key
allows more machines (the More devices email on License delivery, which
you can turn off). If you send your own mail, the
license.upgradedwebhook is where you tell them:
{ "type": "license.upgraded", "data": { "key": "MYPROD-9K4T-2M8P-XQ7V-H3DW", "product": "my-product", "email": "[email protected]", "upgrade": "devices", "session": "cs_live_a1B2c3D4", "versions": { "minMajor": 1, "maxMajor": 2, "upgradeUntil": null }, "entitlements": {}, "deviceLimit": 5 }} See also: Sell an upgrade, Refunds and disputes.
Who can activate
By default anyone who has a key can activate it on a new device. A license model can instead let only the person the key was sold to do it. In the model's settings, choose Who can activate:
The default.
Asks a new device for the email the key was sold to, and refuses any other. This stops a key being shared casually. It does not stop someone who knows the buyer's email.
Asks for the email, then emails a six-digit code to it, and asks for that too. This proves the email is theirs.
- It needs email to work: if the code cannot be sent, a new device cannot activate until it can.
- A product that sends its own customer email (You send them on the License delivery tab) cannot use it.
Your app has to ask
Every SDK takes both the email and the code, each in its own idiom (see the SDKs),
and so does your own call to the activate endpoint. Since @keygrant/electron 0.7.0, the .NET,
Rust, Swift and C++ SDKs 0.6.0, and Dart's first version (see
Which version has what).
- In Electron, that is
activate(key, { email, code }). - An app built on an older SDK cannot ask, so do not lock a model sold to one.
-
The endpoint returns
user-email-requiredanduser-code-requiredto tell the app which to ask for (the SDK, or the endpoint's errors). - The email is compared with the one on the key, without regard to case, and a wrong one is refused without saying what the right one is.
Rules of a locked key
Only a new device. A device that already holds a seat, a renewal, a deactivation and an app running offline are never asked, so turning a lock on, or an outage of email or of KeyGrant, never stops an app that is already activated.
- A key that has no seats left is refused
limitas before, with no code sent.
Lasts 10 minutes and works once. A new code replaces the one before it.
- At most three codes are sent for a key an hour.
- After five wrong ones in an hour, its codes stop working until the hour is out.
- After ten wrong emails in an hour, the key refuses every email until the hour is out, so a leaked key cannot be used to find out who bought it.
Cannot be locked, and activates as Anyone with the key; its page says so. A test license is never locked.
- Issuing a key from a locked model needs its email (
400 email-requiredover the API).
A license file works offline and never activates, and a model sold as an upgrade makes no key, so both are refused.
- A key file can be locked: its key activates online. But a key file carries the buyer's email, so anyone who has the file has it: choose the code form for key files.
Makes every key out to the buyer's email, so the buyer types it, and reads the code, for each teammate. To give each person their own, issue their keys one at a time to their own emails.
Each key takes the model's choice when it is sold, so changing the model changes later keys only. To change one key, open it and choose Change beside Who can activate; from your server, POST /v1/licenses/:key/user-lock; from a terminal, keygrant licenses user-lock.
- The key's History records each change, and the buyer proving their email with a code.
How a device is identified
The SDKs identify a device by the operating system's own machine ID, hashed so the ID never leaves the machine:
- Windows:
MachineGuidunderHKLM\.SOFTWARE\ Microsoft\ Cryptography - macOS: the
IOPlatformUUID. - Linux:
/etc/machine-id, else/var/lib/dbus/machine-id.
- A machine ID survives renaming the computer; reinstalling Windows or Linux gives a new one.
- When there is no ID to read, the SDK uses the host name, platform and architecture, hashed.
Edge cases
- A Linux ID that changes: an ID stored on an in-memory file system is ignored, because it changes at every boot. So is an ID written during the current boot, as it is on the first boot after an install.
- The SDK then uses the host name, and the seat moves to the machine ID at a check-in after a later boot.
- A slow machine ID: if reading it takes too long (2 seconds for a status check, 10 seconds for an activation), a status check skips the device check, and an activation uses the host name.
-
activate()returnsnetworkinstead when this install was activated under the machine ID before.
Holding a license to its device
A seat activated with the machine ID is held to that machine. Its lease carries the machine's hash, so a
license file copied to another machine is refused, offline and online, with reason device.
The customer activates again on the new machine, which takes a seat of its own.
KeyGrant does not refuse a legitimate customer because of how their machine is identified:
- A seat activated under the host name, or by an SDK that reported no fingerprint kind, is not held, because a host name changes when the computer is renamed.
-
It becomes held at the first check-in that reports the machine ID. A seat keyed by the host name moves to
the machine ID at that check-in, and a
device.rekeyedwebhook is sent once.
Turn device hold off
Set deviceHold: false for:
- an app that runs on pooled virtual desktops, where each sign-in may land on a different machine with the same license file;
- a license file in a home folder shared between machines, unless your app's own storage keeps the license on the local machine.
Note
Seats are then not held to a device, but the device limit still applies. With device hold off, KeyGrant cannot spot a license used on several machines.
Machines cloned from one image share one machine ID, so they are one device to KeyGrant. Give each clone its own machine ID before it first runs the app.
A license used on several machines
When a seat is seen on a second machine within 30 days, KeyGrant reports it:
- The key's Devices tab shows how many machines the seat was seen on, and how many of them were refused.
-
A
device.sharedwebhook is sent immediately the first time, then at most once an hour per seat when the count has grown. - Up to 20 machines are counted per seat.
The report itself refuses nothing, since a reinstall can give a legitimate machine a new ID. A seat held to a
machine already refuses every other machine with reason device, and a seat that is not held
keeps working on both. It is up to you whether to release the seat, revoke the key, or do nothing.