Documentation

Device activations

A license can be bound to a fixed number of machines (set by the plan's maxActivations). KeyStack tracks each binding as a row in LicenseActivation, identified by a fingerprint you generate on the device — typically a stable hash of hostname + OS + a UUID stored in the user's home directory.

The three endpoints below let your product check out / check in / renew its activation.


POST /v1/activate

Claim or refresh an activation slot for the current device.

POST /v1/activate
Authorization: Bearer ak_live_4f2a...
X-KeyStack-Timestamp: 1731600000
X-KeyStack-Signature: 7b3d8a1f...
 
{
  "key": "KS-7F3K9-9XYLM-4N2A1-Q7C9F-WT2K",
  "fingerprint": "a3f9e1b84cf7-windows-amd64-7f",
  "hostname": "ALICE-DESKTOP",
  "os": "Windows 11",
  "metadata": { "appVersion": "2.4.1" }
}

Response — slot acquired

{
  "valid": true,
  "activationId": "ckxa1bc...",
  "activations": { "used": 2, "max": 3 }
}

Response — limit reached

{
  "valid": false,
  "reason": "limit_reached",
  "activations": { "used": 3, "max": 3 }
}

Other reason values: not_found, expired, frozen, revoked.

Calling activate again with the same fingerprint is idempotent — it just refreshes lastSeenAt and reactivates if you'd previously deactivated this device.


POST /v1/deactivate

Release an activation slot — call this from your uninstaller, or from a "sign out everywhere" button in your settings UI.

POST /v1/deactivate
Authorization: Bearer ak_live_4f2a...
 
{
  "key": "KS-7F3K9-9XYLM-4N2A1-Q7C9F-WT2K",
  "fingerprint": "a3f9e1b84cf7-windows-amd64-7f"
}

You can target a specific row by activationId instead of fingerprint. The response is:

{ "deactivated": true }

A false response means the row was already deactivated — safe to ignore.


POST /v1/heartbeat

Keep lastSeenAt fresh so the dashboard can show "online now" and so future analytics work. Call this on a 5–15 minute timer while your product is running.

POST /v1/heartbeat
Authorization: Bearer ak_live_4f2a...
 
{
  "key": "KS-7F3K9-9XYLM-4N2A1-Q7C9F-WT2K",
  "fingerprint": "a3f9e1b84cf7-windows-amd64-7f"
}
{ "ok": true, "lastSeenAt": "2026-05-15T20:14:11.000Z" }

If the activation has been deactivated server-side (or never existed), you'll get 409 license/activation-limit — at that point call /v1/activate to claim a fresh slot.