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.