ExisOne Client SDK
Embed our cross-platform .NET library to generate hardware IDs, activate and validate licenses, and send support tickets.
ExisOne.Client · Version: 0.6.0 · TFMs: net8.0, net9.0
Install
dotnet add package ExisOne.Client --version 0.6.0
Initialize
using ExisOne.Client;
var client = new ExisOneClient(new ExisOneClientOptions {
BaseUrl = "https://your-api-host", // must be https
AccessToken = "exo_at_<public>_<secret>", // create in Access Tokens UI
OfflinePublicKey = null // optional: set for offline license validation
});
// Optional: change base URL later
client.WithBaseUrl("https://another-host");
// Library version
var sdkVersion = client.GetVersion();
BaseUrl is not hard-coded; you may also set environment variable EXISONE_BASEURL.
For offline license validation, set OfflinePublicKey to your tenant's RSA public key (PEM format).
Obtain this from the Crypto Keys page.
Capabilities
- Hardware ID:
GenerateHardwareId()— cross-platform fingerprint (salted SHA-256) - Activate Updated in 0.5.0:
ActivateAsync(key, email, hardwareId, productName, version?)→ returnsActivationResultwith success/error details and server version info - Validate:
ValidateAsync(key, hardwareId)→ booleanValidateAsync(hardwareId, productName, activationKey?, version?)→ returns(isValid, status, expirationDate, features[], serverVersion, minimumRequiredVersion)Updated in 0.5.0
- Deactivate:
DeactivateAsync(key, hardwareId, productName)(requires the same hardware) - Generate key:
GenerateActivationKeyAsync(productName, email, planId?, validityDays?)(requiresgenerate) - Support ticket:
SendSupportTicketAsync(productName, email, subject, message)(requiresemail) - Offline Validation:
ValidateOffline(offlineCode, hardwareId)→ validates locally without server connectionValidateSmartAsync(keyOrCode, hardwareId, productName?)→ auto-detects online/offline, falls back gracefully; includesServerVersionandMinimumRequiredVersionUpdated in 0.5.0DeactivateSmartAsync(keyOrCode, hardwareId, productName)→ opportunistic server sync
- Version Enforcement New in 0.5.0:
- Pass your app's version during activation and validation
- Server returns
serverVersionandminimumRequiredVersionso you can notify users of updates - When enforcement is enabled on the product, outdated clients receive
version_outdatedstatus
Quickstart
// 1) Hardware ID (store locally)
var hwid = client.GenerateHardwareId();
// 2) Activation with version (user enters key/email)
var result = await client.ActivateAsync(activationKey, userEmail, hwid, "MyProduct", version: "1.0.0");
if (!result.Success) {
if (result.ErrorCode == "version_outdated")
Console.WriteLine($"Please upgrade to version {result.MinimumRequiredVersion}");
else
Console.WriteLine(result.ErrorMessage);
}
// 3) Validate on app start with version check (requires 'verify' permission)
var (isValid, status, exp, features, serverVer, minVer) =
await client.ValidateAsync(hwid, "MyProduct", activationKey, version: "1.0.0");
if (status == "version_outdated")
Console.WriteLine($"Update required: minimum version is {minVer}");
else if (serverVer != null && serverVer != "1.0.0")
Console.WriteLine($"Update available: v{serverVer}");
// 4) Optional: Deactivate from the same hardware
bool deactivated = await client.DeactivateAsync(activationKey, hwid, "MyProduct");
// 5) (Publisher tooling) Generate a new key for a product
var responseJson = await client.GenerateActivationKeyAsync("MyProduct", "user@example.com", planId: 1);
// 6) Submit support ticket from client
await client.SendSupportTicketAsync("MyProduct", userEmail, "Subject", "Message body");
Offline License Validation
For customers without internet access, generate offline activation codes from the License Keys page by providing their Hardware ID. These codes are RSA-signed and validated locally.
Setup
// Configure with your tenant's RSA public key for offline validation
var client = new ExisOneClient(new ExisOneClientOptions {
BaseUrl = "https://your-api-host",
OfflinePublicKey = @"-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A...
-----END PUBLIC KEY-----"
});
Smart Validation (Recommended)
Auto-detects online vs offline keys based on format. Falls back to offline validation if server is unreachable.
var hwid = client.GenerateHardwareId();
// Works with both online keys (XXXX-XXXX-XXXX-XXXX) and offline codes
var result = await client.ValidateSmartAsync(licenseKeyOrOfflineCode, hwid, "MyProduct");
if (result.IsValid) {
Console.WriteLine($"Licensed until: {result.ExpirationDate}");
Console.WriteLine($"Offline mode: {result.WasOffline}");
Console.WriteLine($"Features: {string.Join(",", result.Features ?? Array.Empty<int>())}");
} else {
Console.WriteLine($"Invalid: {result.ErrorMessage}");
}
Direct Offline Validation (No Network)
// Validate completely offline - no server calls
var offlineResult = client.ValidateOffline(offlineCode, hwid);
if (offlineResult.IsValid) {
Console.WriteLine($"Product: {offlineResult.ProductName}");
Console.WriteLine($"Expires: {offlineResult.ExpirationDate}");
} else if (offlineResult.IsExpired) {
Console.WriteLine("License expired");
} else if (offlineResult.HardwareMismatch) {
Console.WriteLine("Wrong machine - license bound to different hardware");
} else {
Console.WriteLine($"Invalid: {offlineResult.ErrorMessage}");
}
Deactivation with Opportunistic Sync
// Tries to notify server, but succeeds locally even if offline
var result = await client.DeactivateSmartAsync(keyOrCode, hwid, "MyProduct");
Console.WriteLine($"Success: {result.Success}, Server notified: {result.ServerNotified}");
Version Enforcement New in 0.5.0
Force users to upgrade their software by enabling version enforcement on your product. When enabled, activation and validation will fail if the client version is below the minimum required version.
How It Works
- Set Minimum Required Version on your product (e.g., "2.0.0")
- Enable Enforce Version Check in the Product Management page
- Client apps send their version during activation/validation
- If client version < minimum, server returns
version_outdatedstatus - Server always returns
serverVersionso clients know when updates are available
Activation with Version
var result = await client.ActivateAsync(key, email, hwid, "MyProduct", version: "1.5.0");
if (!result.Success) {
if (result.ErrorCode == "version_outdated") {
Console.WriteLine($"Your version 1.5.0 is outdated.");
Console.WriteLine($"Minimum required: {result.MinimumRequiredVersion}");
Console.WriteLine($"Latest available: {result.ServerVersion}");
} else {
Console.WriteLine($"Activation failed: {result.ErrorMessage}");
}
} else {
Console.WriteLine($"Activated! Server version: {result.ServerVersion}");
}
Validation with Version Check
var (isValid, status, exp, features, serverVer, minVer) =
await client.ValidateAsync(hwid, "MyProduct", activationKey, version: "1.5.0");
if (status == "version_outdated") {
// Force user to upgrade
Console.WriteLine($"Please upgrade to version {minVer} or later");
} else if (isValid) {
// Optionally notify about available updates
if (serverVer != "1.5.0")
Console.WriteLine($"Update available: v{serverVer}");
}
Smart Validation with Version
var result = await client.ValidateSmartAsync(keyOrCode, hwid, "MyProduct");
// ServerVersion and MinimumRequiredVersion are included in the result
if (result.ServerVersion != null)
Console.WriteLine($"Server version: {result.ServerVersion}");
if (result.MinimumRequiredVersion != null)
Console.WriteLine($"Minimum required: {result.MinimumRequiredVersion}");
Offline Workflow
- Customer runs your app and sees their Hardware ID (from
GenerateHardwareId()) - Customer contacts you with their Hardware ID (email/phone/support ticket)
- You generate an Offline Activation Code in the License Keys page
- Customer enters the code into your app
- Your app validates locally using
ValidateOffline()orValidateSmartAsync()
Permissions
| Method | Required Permission | Notes |
|---|---|---|
ValidateAsync | verify | Server enforces in /api/license/validate |
GenerateActivationKeyAsync | generate | Publisher operations |
DeactivateAsync | None | Allowed only when server-side hardware matches bound license |
SendSupportTicketAsync | email | Sends email via tenant/global SMTP |
ActivateAsync | None | Current API does not require a specific scope |
API Reference
// Version
string GetVersion();
// Hardware
string GenerateHardwareId();
// Activation (Updated in 0.5.0 - now returns ActivationResult)
Task<ActivationResult> ActivateAsync(string activationKey, string email, string hardwareId, string? version = null);
Task<ActivationResult> ActivateAsync(string activationKey, string email, string hardwareId, string productName, string? version = null);
// Validation (Online) - Updated in 0.5.0 to include serverVersion and minimumRequiredVersion
Task<bool> ValidateAsync(string activationKey, string hardwareId);
Task<(bool isValid, string status, DateTime? expirationDate, int[] features, string? serverVersion, string? minimumRequiredVersion)> ValidateAsync(string hardwareId, string productName, string? activationKey = null, string? version = null);
// Validation (Offline)
OfflineValidationResult ValidateOffline(string offlineCode, string hardwareId);
Task<SmartValidationResult> ValidateSmartAsync(string keyOrCode, string hardwareId, string? productName = null);
// Deactivation
Task<bool> DeactivateAsync(string activationKey, string hardwareId, string productName);
Task<DeactivationResult> DeactivateSmartAsync(string keyOrCode, string hardwareId, string productName);
// Generation (publisher)
Task<string> GenerateActivationKeyAsync(string productName, string email, int? planId = null, int? validityDays = null);
// Support
Task SendSupportTicketAsync(string productName, string email, string subject, string message);
// Configuration
IExisOneClient WithBaseUrl(string baseUrl);
// Result Types
class ActivationResult { // New in 0.5.0
bool Success;
string? ErrorCode; // e.g., "version_outdated"
string? ErrorMessage;
string? ServerVersion; // Current product version on server
string? MinimumRequiredVersion; // Minimum required when enforcement is on
string? LicenseData; // Raw license data on success
}
class OfflineValidationResult { bool IsValid; string? ErrorMessage; string? ProductName; DateTime? ExpirationDate; int[]? Features; bool IsExpired; bool HardwareMismatch; }
class SmartValidationResult { // Updated in 0.5.0
bool IsValid; string Status; DateTime? ExpirationDate; int[]? Features;
bool WasOffline; string? ErrorMessage; string? ProductName;
string? ServerVersion; // New in 0.5.0
string? MinimumRequiredVersion; // New in 0.5.0
}
class DeactivationResult { bool Success; bool ServerNotified; string? ErrorMessage; }
Common Errors
- 403 verify permission required: Add
verifyto the token in Access Tokens UI. - Activation key not found in this tenant: Token and key must belong to same tenant.
- 400 Bad Request on activation: Ensure product name is correct (or use overload without productName).
- version_outdated New: Client version is below the minimum required. Check
MinimumRequiredVersionin the response and prompt user to upgrade.
Demo & Examples
A complete working demo console application is available on GitHub: ExisOne.Client.Console
The demo includes interactive examples of all SDK features:
- Hardware ID generation
- License activation with version check
- Simple and rich validation
- Smart validation (online/offline auto-detect)
- Offline validation
- Deactivation (standard and smart)
- Support ticket submission
- Key generation (publisher feature)
git clone https://github.com/exisllc/ExisOne.Client.Console.git cd ExisOne.Client.Console dotnet run --project ExisOne.Client.Console
Changelog
- 0.6.0: New Consistent Expiration Dates —
Validation now always returns
expirationDateeven for invalid/inactive licenses; for invalid cases, expiration is calculated from device record creation date + trial days (if product found) or just creation date; device license records are now cleared when a license is deactivated; new device history API endpoint for viewing all license events by hardware ID. - 0.5.0: Version Enforcement —
ActivateAsync()now accepts optionalversionparameter and returnsActivationResultwith structured error handling;ValidateAsync()tuple now returnsserverVersionandminimumRequiredVersion;SmartValidationResultincludes version info; newversion_outdatedstatus when client version is below minimum required; server always returns current product version for update notifications. - 0.4.0: Offline License Validation — Added
ValidateOffline(),ValidateSmartAsync(),DeactivateSmartAsync(); newOfflinePublicKeyoption for RSA-signed offline codes; smart auto-detection of online vs offline keys; opportunistic server sync for deactivation. - 0.3.0: Added
DeactivateAsync(...); license history now recordsIpAddressandCountryon activation/validation/deactivation; docs updated. - 0.2.0: Added rich
ValidateAsync(hardwareId, productName, ...)overload returning status/expiration/features; docs updated. - 0.1.1: Multi-target
net8.0/net9.0,ValidateAsyncuses secure/api/license/validate, addedGetVersion(). - 0.1.0: Initial release.