POST /activate

POST /api/v1/activate

Validates the key and registers an installation. A new count-based activation consumes a seat; node-locked reactivation with the same device ID reuses its existing seat. Use this only when a customer "registers" your software on a specific machine for the first time. Once the key's max activations are reached, this endpoint returns an error.

Nonce required: You must call GET /api/v1/nonce first and include the returned value as the nonce field. Nonces are single-use and expire in 5 minutes.

Request body fields

FieldTypeRequiredDescription
licenseKeystringYesThe plaintext license key (PERMIT-XXXX-XXXX-XXXX-XXXX format)
noncestringYesSingle-use token from GET /api/v1/nonce — prevents replay attacks
deviceIdstringNoSHA-256 hardware fingerprint — required for node-locked licenses
deviceNamestringNoHuman-readable device label (e.g. "John-MacBook-Pro"), shown in admin panel
versionstringNoYour app version (e.g. "2.3.1") — validated against MinVersion/MaxVersion on the license
userEmailstringNoEnd-user's email address — stored for B2B named-user audit trail, visible in admin panel
JSON Body — full example
{
  "licenseKey": "PERMIT-A3K7-MN2P-QR9X-TZ5W",
  "nonce":      "a3f82b1c9e4d7f06bc2e5a1d3c8f7e92",
  "deviceId":   "a3f8d2b1c9e4...",
  "deviceName": "John-MacBook-Pro-M3",
  "version":    "2.3.1",
  "userEmail":  "[email protected]"
}
cURL — two-step flow (fetch nonce then activate)
# Step 1: get a nonce
NONCE=$(curl -s https://api.permitcore.dev/api/v1/nonce | python3 -c "import sys,json; print(json.load(sys.stdin)['nonce'])")

# Step 2: activate
curl -X POST https://api.permitcore.dev/api/v1/activate \
  -H "Content-Type: application/json" \
  -d "{\"licenseKey\": \"PERMIT-A3K7-MN2P-QR9X-TZ5W\", \"nonce\": \"$NONCE\"}"

Success response (200 OK)

JSON
{
  "isValid": true,
  "productName": "Acme Video Editor Pro",
  "remainingActivations": 2,
  "expiresAt": null,
  "features": ["export", "api"],
  "isTrial": false,
  "nodeLocked": true,
  "offlineGraceDays": 7
}

Max activations reached (200, isValid: false)

JSON
{
  "isValid": false,
  "message": "Maximum activations reached for this license",
  "errorCode": "SeatsExhausted"
}
Activation is atomic: The counter is incremented using a database-level atomic operation. You don't need to worry about race conditions even if multiple machines try to activate the same key simultaneously.