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 deviceLimit it was issued or imported with, or a Stripe checkout's deviceLimit metadata.

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 a device.limit_reached webhook 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 deviceLimit when 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 limit until 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 returns released: 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 devices and free-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 invalid with reason revoked; the app must then be activated again.
  • Each release sends a device.released webhook.

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.
WhereHow 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 keyOpen 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.released webhook is sent with reason: 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:

  1. 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.
  2. Choose Devices under What it upgrades.
  3. Set Devices it adds: how many one purchase adds, such as 2 for "Two more devices". Buying two at once adds twice as many.
  4. 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.
App
// 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.upgraded webhook is where you tell them:
Body
{  "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:

Anyone with the key

The default.

Only the buyer: they type their email

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.

Only the buyer: a code is emailed to them

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-required and user-code-required to 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

Who is asked

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 limit as before, with no code sent.
A code

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.
A key with no email

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-required over the API).
Models that cannot be locked

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.
A sale of several keys

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.

Changing one key

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: MachineGuid under HKLM\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() returns network instead 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.rekeyed webhook 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.shared webhook 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.