Skip to content
Thrive Tech Services
Thrive Tech Services
HomeServicesProductsDocsEnterpriseContactAbout
LoginRegister

Activation API

The Activation API handles license activation, validation, device management, and session tracking for ThriveTech products.

Base URL: /api/v1/activate

Authentication: All requests must include either:

  • Product API Key (PAK): Authorization: Bearer pak_live_xxxx
  • Channel API Key: X-Channel-API-Key: ch_live_xxxx

Endpoints

#MethodEndpointDescription
1POST/api/v1/activate/trialActivate a trial license
2POST/api/v1/activate/purchaseActivate a purchased license
3POST/api/v1/activate/validateValidate a license token
4POST/api/v1/activate/deactivateDeactivate current device
5GET/POST/api/v1/activate/check-trialCheck trial eligibility
6GET/api/v1/activate/devicesList activated devices
7POST/api/v1/activate/devices/:deviceId/deactivateDeactivate device by ID
8POST/api/v1/activate/heartbeatSession heartbeat
9GET/api/v1/activate/sessionsList active sessions
10POST/api/v1/activate/sessions/:sessionId/terminateTerminate session

1. Trial Activation

POST /api/v1/activate/trial

Request Body

json
{
"deviceFingerprint": "unique-hardware-identifier-min-16-chars",
"deviceInfo": {
"name": "My MacBook Pro",
"type": "laptop",
"osType": "macOS",
"osVersion": "14.0",
"appVersion": "1.0.0"
},
"userInfo": {
"email": "user@example.com",
"firstName": "John",
"lastName": "Doe"
}
}

Success Response (200)

json
{
"success": true,
"activation": {
"id": "uuid",
"licenseToken": "eyJhbGciOiJIUzI1NiIs...",
"expiresAt": "2026-03-05T00:00:00.000Z",
"trialDaysRemaining": 14,
"features": ["basic", "export", "sync"],
"deviceId": "uuid",
"activationType": "trial"
},
"purchase": {
"purchase_url": "https://example.com/buy",
"has_purchase_url": true
}
}

Errors

CodeErrorDescription
400TRIAL_ALREADY_USEDDevice has already used a trial
400TRIAL_NOT_ENABLEDTrial not enabled for this product
400DEVICE_BLOCKEDDevice has been blocked

Notes: One trial per device per product. If the device has an active trial, calling this returns the existing trial with a fresh token.


2. Purchase Activation

POST /api/v1/activate/purchase

Request Body (Direct License Key)

json
{
"deviceFingerprint": "unique-hardware-identifier",
"deviceInfo": { "type": "desktop", "osType": "Windows", "appVersion": "1.0.0" },
"storeReceipt": {
"channelType": "direct",
"receiptData": "XXXX-XXXX-XXXX-XXXX"
},
"previousTrialToken": "optional-trial-token-for-conversion"
}

Request Body (Store Purchase)

json
{
"deviceFingerprint": "unique-hardware-identifier",
"deviceInfo": { "type": "desktop", "osType": "Windows", "appVersion": "1.0.0" },
"storeReceipt": {
"channelType": "microsoft_store",
"receiptData": "store-receipt-or-token",
"transactionId": "store-transaction-id",
"productId": "store-product-sku"
}
}

Channel Types

ValueDescription
directLicense key from direct sales
microsoft_storeMicrosoft Store purchase
google_playGoogle Play purchase
apple_app_storeApple App Store purchase

Success Response (200)

json
{
"success": true,
"activation": {
"id": "uuid",
"licenseToken": "eyJhbGciOiJIUzI1NiIs...",
"expiresAt": "2027-01-15T00:00:00.000Z",
"features": ["basic", "advanced", "professional"],
"activationType": "purchase",
"productTier": "professional",
"convertedFromTrial": false,
"subscription": {
"id": "sub_12345",
"status": "active",
"currentPeriodEnd": "2027-01-15T00:00:00.000Z"
}
}
}

Seat Limit Reached (400)

When a license reaches its max device limit, the API returns the active device list:

json
{
"success": false,
"error": {
"code": "SEAT_LIMIT_REACHED",
"message": "Maximum devices reached. Deactivate a device to continue.",
"activeDevices": [
{
"id": "device-uuid-1",
"deviceName": "Work Laptop",
"deviceType": "laptop",
"activatedAt": "2026-01-01T00:00:00.000Z",
"lastActiveAt": "2026-01-10T00:00:00.000Z"
}
],
"seatInfo": { "maxSeats": 2, "usedSeats": 2, "availableSeats": 0 }
}
}

Errors

CodeErrorDescription
400SEAT_LIMIT_REACHEDMax devices — includes device list for management
400LICENSE_KEY_INVALIDInvalid license key format
400LICENSE_KEY_NOT_FOUNDLicense key not found
400LICENSE_KEY_EXPIREDLicense has expired
400LICENSE_KEY_REVOKEDLicense has been revoked
400STORE_VALIDATION_FAILEDStore receipt validation failed

Notes: Reactivation on a previously activated device doesn't consume an additional seat. Pass previousTrialToken to convert trial to paid while maintaining history.


3. License Validation

POST /api/v1/activate/validate

Call at app startup and every 24 hours.

Request Body

json
{
"licenseToken": "eyJhbGciOiJIUzI1NiIs...",
"deviceFingerprint": "unique-hardware-identifier"
}

Success Response (200)

json
{
"valid": true,
"license": {
"type": "subscription",
"expiresAt": "2027-01-15T00:00:00.000Z",
"features": ["basic", "advanced", "professional"],
"status": "active",
"daysRemaining": 45
},
"device": { "id": "device-uuid", "name": "My MacBook" }
}

Errors

CodeErrorDescription
400INVALID_TOKENToken malformed or invalid
400TOKEN_EXPIREDToken has expired
400DEVICE_MISMATCHToken not valid for this device
400LICENSE_REVOKEDLicense has been revoked
400LICENSE_EXPIREDLicense has expired

Notes: Implement a 7-day offline grace period. Cache results locally to reduce API calls. Use the features array for feature gating.


4. Device Deactivation

POST /api/v1/activate/deactivate

Request Body

json
{
"licenseToken": "eyJhbGciOiJIUzI1NiIs...",
"deviceFingerprint": "unique-hardware-identifier",
"reason": "User uninstalled application"
}

Call when the user uninstalls or signs out. The seat is freed immediately.


5. Trial Eligibility Check

GET /api/v1/activate/check-trial?deviceFingerprint=xxx POST /api/v1/activate/check-trial

Response (Eligible)

json
{ "eligible": true, "trialDuration": 14, "features": ["basic", "export", "sync"] }

Response (Not Eligible)

json
{ "eligible": false, "reason": "A trial has already been used on this device", "expired": true }

6. List Devices

GET /api/v1/activate/devices?licenseToken=xxx&deviceFingerprint=current

Response

json
{
"success": true,
"devices": [
{
"id": "device-uuid-1",
"deviceName": "Work Laptop",
"deviceType": "laptop",
"osType": "Windows",
"activatedAt": "2026-01-01T00:00:00.000Z",
"lastActiveAt": "2026-01-15T10:30:00.000Z",
"isCurrentDevice": true
}
],
"seatInfo": { "maxSeats": 3, "usedSeats": 2, "availableSeats": 1 }
}

Use this to build a "Manage Devices" UI. Mark isCurrentDevice: true with a "This device" label.


7. Deactivate Device by ID

POST /api/v1/activate/devices/:deviceId/deactivate

Request Body

json
{
"licenseToken": "eyJhbGciOiJIUzI1NiIs...",
"reason": "User removed device"
}

Response

json
{ "success": true, "message": "Device deactivated successfully", "availableSeats": 2 }

8. Session Heartbeat

POST /api/v1/activate/heartbeat

Send every 5 minutes while the app is active. Sessions missing heartbeats for 10+ minutes are automatically terminated.

Request Body

json
{
"licenseToken": "eyJhbGciOiJIUzI1NiIs...",
"deviceFingerprint": "unique-hardware-identifier",
"sessionId": "optional-existing-session-id"
}

Response

json
{
"success": true,
"sessionId": "session-uuid",
"nextHeartbeatDue": "2026-01-15T10:35:00.000Z",
"sessionValid": true
}

9. List Sessions

GET /api/v1/activate/sessions?licenseToken=xxx

Response

json
{
"success": true,
"sessions": [
{
"id": "session-uuid-1",
"deviceName": "Work Laptop",
"startedAt": "2026-01-15T08:00:00.000Z",
"lastHeartbeat": "2026-01-15T10:30:00.000Z",
"isCurrentSession": true
}
],
"maxConcurrent": 3,
"currentCount": 1
}

10. Terminate Session

POST /api/v1/activate/sessions/:sessionId/terminate

Request Body

json
{
"licenseToken": "eyJhbGciOiJIUzI1NiIs...",
"reason": "User signed out remotely"
}

Error Code Reference

Activation Errors

CodeDescription
TRIAL_ALREADY_USEDDevice has already used a trial for this product
TRIAL_NOT_ENABLEDTrial not enabled for this product
DEVICE_BLOCKEDDevice has been blocked
SEAT_LIMIT_REACHEDLicense at maximum device limit

License Key Errors

CodeDescription
LICENSE_KEY_INVALIDInvalid key format
LICENSE_KEY_NOT_FOUNDKey not found
LICENSE_KEY_EXPIREDKey has expired
LICENSE_KEY_REVOKEDKey has been revoked

Store Validation Errors

CodeDescription
STORE_RECEIPT_INVALIDMalformed receipt
STORE_VALIDATION_FAILEDStore API validation failed
STORE_PRODUCT_MISMATCHProduct ID doesn't match
STORE_SUBSCRIPTION_CANCELLEDSubscription was cancelled
STORE_REFUNDEDPurchase was refunded

Validation Errors

CodeDescription
INVALID_TOKENToken malformed or tampered
TOKEN_EXPIREDToken has expired
DEVICE_MISMATCHToken not valid for this device
LICENSE_REVOKEDLicense has been revoked
LICENSE_EXPIREDLicense has expired

Session Errors

CodeDescription
CONCURRENT_SESSION_LIMIT_REACHEDMax concurrent sessions reached
SESSION_NOT_FOUNDSession ID not found
SESSION_ALREADY_TERMINATEDSession already terminated

Implementation Checklist

Required

  • Generate consistent device fingerprint (hash of hardware IDs, min 16 chars)
  • Store license token securely (encrypted local storage)
  • Handle SEAT_LIMIT_REACHED with device management UI
  • Implement periodic validation (startup + every 24h)
  • Call deactivate on uninstall/sign-out
  • Session heartbeat every 5 minutes
  • "Manage Devices" UI for self-service
  • Offline grace period (7 days recommended)
  • Cache validation results locally
  • Trial-to-purchase conversion flow
API Reference

Was this helpful?