SDK AI Prompt
Copy/paste this prompt into your AI assistant (e.g., GitHub Copilot Chat, Cursor, ChatGPT) to integrate the ExisOne Client SDK into your application.
Prompt
You're assisting me in integrating the ExisOne Client SDK for software licensing.
GOAL
- Generate a stable hardware ID on first run
- Activate a license with user input (activation key + email) and report app version
- Validate the license on every app start (online or offline) with version checking
- Check for software updates by comparing client version to server version
- Deactivate the license from the same hardware when requested
- Support offline customers with RSA-signed offline activation codes
- Submit support tickets from within the app
CONTEXT
- SDK package: ExisOne.Client (version 0.6.0)
- Target frameworks: net8.0 or net9.0
- I have an API base URL and an access token (format: exo_at_<public>_<secret>)
- Validate requires 'verify' permission on the access token
- For offline validation, I have an RSA public key (PEM format) from the Crypto Keys page
- Server may enforce minimum version requirements - client must handle version_outdated status
DEMO PROJECT
- Full working example: https://github.com/exisllc/ExisOne.Client.Console
- Clone and run: git clone https://github.com/exisllc/ExisOne.Client.Console.git
REQUIREMENTS
1) Add the NuGet package:
dotnet add package ExisOne.Client --version 0.6.0
2) Initialize the client as a singleton/service:
using ExisOne.Client;
var client = new ExisOneClient(new ExisOneClientOptions {
BaseUrl = "https://YOUR-API-HOST",
AccessToken = "exo_at_PUBLIC_SECRET",
OfflinePublicKey = @"-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A...
-----END PUBLIC KEY-----" // Optional: for offline license validation
});
// Log SDK version
Console.WriteLine($"ExisOne SDK: {client.GetVersion()}");
3) Hardware ID:
- On first run, compute client.GenerateHardwareId(), persist locally (e.g., config/user store)
- Reuse the persisted value thereafter
- Display to user so they can request offline licenses if needed
4) Activation flow with version (Updated in 0.5.0):
- Ask for Activation Key (or Offline Code) and Email
- For online keys with version check:
var result = await client.ActivateAsync(key, email, hardwareId, "MyProduct", version: "1.0.0");
if (!result.Success) {
if (result.ErrorCode == "version_outdated") {
// User must upgrade before activating
ShowError($"Please upgrade to version {result.MinimumRequiredVersion}");
} else {
ShowError(result.ErrorMessage);
}
} else {
// Activation successful - optionally notify about updates
if (result.ServerVersion != "1.0.0")
ShowInfo($"Update available: v{result.ServerVersion}");
}
- For offline codes: use ValidateOffline() or ValidateSmartAsync() - no activation needed
5) Validation with version check (Updated in 0.5.0):
- Rich validation with version:
var (isValid, status, exp, features, serverVer, minVer) =
await client.ValidateAsync(hwid, "MyProduct", activationKey, version: "1.0.0");
if (status == "version_outdated") {
// Force upgrade - license valid but version too old
ShowError($"Please upgrade to version {minVer} to continue");
return;
}
if (isValid) {
// Optionally check for updates
if (serverVer != null && serverVer != "1.0.0")
ShowInfo($"Update available: v{serverVer}");
}
- Smart validation (handles online/offline):
var result = await client.ValidateSmartAsync(keyOrCode, hardwareId, "MyProduct");
// result.ServerVersion and result.MinimumRequiredVersion available
- Legacy simple validation: var ok = await client.ValidateAsync(key, hardwareId);
6) Offline-only validation (no network):
- var result = client.ValidateOffline(offlineCode, hardwareId);
- Check result.IsValid, result.IsExpired, result.HardwareMismatch
- Use when you know the user has an offline code and want zero network calls
7) Deactivation flow:
- For smart deactivation (tries server, succeeds locally if offline):
var result = await client.DeactivateSmartAsync(keyOrCode, hardwareId, "MyProduct");
Console.WriteLine($"Success: {result.Success}, Server notified: {result.ServerNotified}");
- Legacy online-only: await client.DeactivateAsync(key, hardwareId, "MyProduct");
8) Support tickets:
- Provide a form (product, email, subject, message)
- Call: await client.SendSupportTicketAsync(productName, email, subject, message);
9) Offline license workflow for customers without internet:
- Customer sees their Hardware ID in your app (from GenerateHardwareId())
- Customer contacts you (email/phone) with their Hardware ID
- You generate an Offline Activation Code in the License Keys dashboard
- Customer enters the long code into your app
- Your app validates using ValidateOffline() or ValidateSmartAsync()
10) Tenancy:
- Ensure the access token belongs to the same tenant that owns the activation keys
11) Version enforcement handling:
- Always pass your app's version during activation and validation
- Handle "version_outdated" status by prompting user to upgrade
- Use ServerVersion to notify users when updates are available
- MinimumRequiredVersion tells you the oldest acceptable version
12) Logging & errors:
- Surface server error bodies from HttpRequestException for troubleshooting
- For offline validation failures, check IsExpired and HardwareMismatch flags
- For version failures, check ErrorCode == "version_outdated"
OFFLINE CODE SECURITY
- Offline codes are RSA-SHA256 signed (Base32 encoded with dashes)
- They embed: product ID, hardware ID, expiration date, email, features
- Cannot be forged, transferred, or modified
- Expiration is checked against local machine time
RESULT TYPES (0.6.0)
- ActivationResult: { Success, ErrorCode, ErrorMessage, ServerVersion, MinimumRequiredVersion, LicenseData }
- SmartValidationResult: { IsValid, Status, ExpirationDate, Features, WasOffline, ErrorMessage, ProductName, ServerVersion, MinimumRequiredVersion }
- ValidateAsync tuple: (isValid, status, expirationDate, features, serverVersion, minimumRequiredVersion)
EXPIRATION DATE BEHAVIOR (0.6.0)
- expirationDate is now ALWAYS returned, even for invalid/inactive licenses
- For invalid licenses: calculated from device record creation date + trial days (if product found)
- If product not found: returns device record creation date
- First-time validation: returns current date as expiration
- This allows clients to always display meaningful expiration information
DELIVERABLES
- Add service registration and configuration code
- Implement activation UI supporting both online keys and offline codes
- Pass app version during activation and validation
- Handle version_outdated status with upgrade prompts
- Optionally notify users when ServerVersion differs from current version
- Use ValidateSmartAsync() for seamless online/offline handling
- Provide code snippets for persistence of hardware ID and license key/code
- Display hardware ID to users for offline license requests
- Ensure async/await usage and exception handling best practices
Please produce idiomatic C# for my stack (WPF/WinForms/ASP.NET/etc. as applicable), with concise methods and no extraneous commentary.
Notes
- See SDK Docs for full API details and permissions.
- Current SDK version:
0.6.0. - Demo Project: github.com/exisllc/ExisOne.Client.Console — complete working example with all SDK features.
- New in 0.6.0: Validation now always returns
expirationDateeven for invalid/inactive licenses; expiration calculated from device record creation date + trial days; device license records cleared on deactivation; new device history API endpoint. - 0.5.0: Version enforcement support — pass client version during activation/validation; handle
version_outdatedstatus; receiveServerVersionandMinimumRequiredVersionfor update notifications;ActivateAsyncnow returns structuredActivationResult. - 0.4.0: Offline license validation with RSA-signed codes, smart validation, opportunistic deactivation sync.
- Get your RSA public key from the Crypto Keys page for offline validation.
- Configure minimum version requirements in the Product Management page.