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
| Field | Type | Required | Description |
|---|---|---|---|
licenseKey | string | Yes | The plaintext license key (PERMIT-XXXX-XXXX-XXXX-XXXX format) |
nonce | string | Yes | Single-use token from GET /api/v1/nonce — prevents replay attacks |
deviceId | string | No | SHA-256 hardware fingerprint — required for node-locked licenses |
deviceName | string | No | Human-readable device label (e.g. "John-MacBook-Pro"), shown in admin panel |
version | string | No | Your app version (e.g. "2.3.1") — validated against MinVersion/MaxVersion on the license |
userEmail | string | No | End-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.