C# SDK
C# SDK
Official C# SDK for LicenseSeat. Add license validation to your .NET apps, Unity games, and Godot projects in minutes.
Building a Unity game? We have a dedicated Unity SDK with full IL2CPP, WebGL, iOS, and Android support. No DLLs - just install via Unity Package Manager.
Installation
NuGet (.NET, Godot)
dotnet add package LicenseSeat
Requirements: .NET Standard 2.0+ (.NET Framework 4.6.1+, .NET Core 2.0+, .NET 5+)
Unity
Option 1: Git URL (Recommended)
- Open Window > Package Manager
- Click + > Add package from git URL...
- Paste:
https://github.com/licenseseat/licenseseat-csharp.git?path=src/LicenseSeat.Unity
Option 2: manifest.json
Add to Packages/manifest.json:
{
"dependencies": {
"com.licenseseat.sdk": "https://github.com/licenseseat/licenseseat-csharp.git?path=src/LicenseSeat.Unity"
}
}
Option 3: OpenUPM
openupm add com.licenseseat.sdk
Pin to a version:
https://github.com/licenseseat/licenseseat-csharp.git?path=src/LicenseSeat.Unity#v0.2.0
Quick Start
using LicenseSeat;
var client = new LicenseSeatClient(new LicenseSeatClientOptions
{
ApiKey = "pk_live_xxxxxxxx",
ProductSlug = "your-product" // Required
});
// Activate a license
var license = await client.ActivateAsync("XXXX-XXXX-XXXX-XXXX");
// Check entitlements
if (client.HasEntitlement("pro-features"))
{
// Enable pro features
}
Static API (Singleton)
For desktop apps where you want global access:
using LicenseSeat;
// Configure once at startup
LicenseSeat.LicenseSeat.Configure("pk_live_xxxxxxxx", "your-product", options =>
{
options.AutoValidateInterval = TimeSpan.FromHours(1);
});
// Use anywhere in your app
await LicenseSeat.LicenseSeat.Activate("LICENSE-KEY");
if (LicenseSeat.LicenseSeat.HasEntitlement("premium"))
{
// Premium features
}
var status = LicenseSeat.LicenseSeat.GetStatus();
var license = LicenseSeat.LicenseSeat.GetCurrentLicense();
// Cleanup on exit
LicenseSeat.LicenseSeat.Shutdown();
Configuration
Basic Configuration
var client = new LicenseSeatClient(new LicenseSeatClientOptions
{
ApiKey = "pk_live_xxxxxxxx",
ProductSlug = "your-product"
});
Advanced Configuration
var client = new LicenseSeatClient(new LicenseSeatClientOptions
{
ApiKey = "pk_live_xxxxxxxx",
ProductSlug = "your-product",
ApiBaseUrl = "https://licenseseat.com/api/v1",
AutoValidateInterval = TimeSpan.FromHours(1),
MaxRetries = 3,
RetryDelay = TimeSpan.FromSeconds(1),
OfflineFallbackMode = OfflineFallbackMode.NetworkOnly,
MaxOfflineDays = 7,
MaxClockSkew = TimeSpan.FromMinutes(5),
HttpTimeout = TimeSpan.FromSeconds(30),
Debug = true
});
Configuration Options
| Option | Type | Default | Description |
|---|---|---|---|
ApiKey |
string |
— | Required. Your publishable API key |
ProductSlug |
string |
— | Required. Your product identifier |
ApiBaseUrl |
string |
https://licenseseat.com/api/v1 |
API endpoint |
AutoValidateInterval |
TimeSpan |
1 hour | Background validation interval (0 = disabled) |
MaxRetries |
int |
3 | Retry attempts for failed requests |
RetryDelay |
TimeSpan |
1 second | Base delay between retries |
OfflineFallbackMode |
OfflineFallbackMode |
Disabled |
Offline validation mode |
MaxOfflineDays |
int |
0 | Offline grace period (0 = disabled) |
MaxClockSkew |
TimeSpan |
5 minutes | Clock tamper tolerance |
HttpTimeout |
TimeSpan |
30 seconds | Request timeout |
Debug |
bool |
false |
Enable debug logging |
Offline Fallback Modes
| Mode | Description |
|---|---|
Disabled |
Offline fallback disabled. Network failures throw exceptions. |
NetworkOnly |
Fall back to offline only for network errors (not 4xx/5xx). Recommended. |
Always |
Fall back to offline on any validation failure. |
License Lifecycle
Activation
var license = await client.ActivateAsync("LICENSE-KEY");
Console.WriteLine($"Activated: {license.Key}");
Console.WriteLine($"Status: {license.Status}");
Console.WriteLine($"Plan: {license.PlanKey}");
Validation
var result = await client.ValidateAsync("LICENSE-KEY");
if (result.Valid)
{
Console.WriteLine("License is valid!");
Console.WriteLine($"Active Seats: {result.License?.ActiveSeats}/{result.License?.SeatLimit}");
}
else
{
Console.WriteLine($"Invalid: {result.Code} - {result.Message}");
}
Deactivation
await client.DeactivateAsync();
Get Status
var status = client.GetStatus();
Console.WriteLine($"Status: {status.StatusType}");
Entitlements
Simple Check
if (client.HasEntitlement("premium"))
{
// Unlock premium features
}
Detailed Check
var entitlement = client.CheckEntitlement("pro-features");
if (entitlement.Active)
{
EnableProFeatures();
}
else
{
switch (entitlement.Reason)
{
case EntitlementInactiveReason.Expired:
ShowRenewalPrompt();
break;
case EntitlementInactiveReason.NotFound:
ShowUpgradePrompt();
break;
case EntitlementInactiveReason.NoLicense:
ShowActivationPrompt();
break;
}
}
Event Handling
// Subscribe to license events
client.Events.On(LicenseSeatEvents.LicenseValidated, _ =>
Console.WriteLine("License validated!"));
client.Events.On(LicenseSeatEvents.ValidationFailed, _ =>
Console.WriteLine("Validation failed!"));
client.Events.On(LicenseSeatEvents.EntitlementChanged, _ =>
Console.WriteLine("Entitlements updated!"));
client.Events.On(LicenseSeatEvents.LicenseActivated, license =>
Console.WriteLine($"Activated: {((License)license).Key}"));
client.Events.On(LicenseSeatEvents.LicenseDeactivated, _ =>
Console.WriteLine("License deactivated"));
Offline Validation
var client = new LicenseSeatClient(new LicenseSeatClientOptions
{
ApiKey = "pk_live_xxxxxxxx",
ProductSlug = "your-product",
OfflineFallbackMode = OfflineFallbackMode.NetworkOnly,
MaxOfflineDays = 7 // Allow 7 days offline
});
// Validate - falls back to cached offline token if network fails
var result = await client.ValidateAsync("LICENSE-KEY");
if (result.Offline)
{
Console.WriteLine("Validated offline with cached license");
}
The SDK automatically fetches and caches Ed25519-signed offline tokens after activation. When offline:
- Validates token signature cryptographically
- Checks token expiration (
exptimestamp) - Detects clock tampering
- Returns cached entitlements
ASP.NET Core Integration
Dependency Injection
// Program.cs
builder.Services.AddLicenseSeatClient("pk_live_xxxxxxxx", "your-product");
// Or with full options:
builder.Services.AddLicenseSeatClient(options =>
{
options.ApiKey = "pk_live_xxxxxxxx";
options.ProductSlug = "your-product";
options.AutoValidateInterval = TimeSpan.FromMinutes(30);
});
Using in Controllers
public class LicenseController : ControllerBase
{
private readonly ILicenseSeatClient _client;
public LicenseController(ILicenseSeatClient client) => _client = client;
[HttpPost("activate")]
public async Task<IActionResult> Activate([FromBody] string licenseKey)
{
var license = await _client.ActivateAsync(licenseKey);
return Ok(new { license.Key, license.Status });
}
[HttpGet("status")]
public IActionResult GetStatus()
{
var status = _client.GetStatus();
return Ok(new { status.StatusType, status.Message });
}
}
Unity Integration
using UnityEngine;
using LicenseSeat;
public class LicenseController : MonoBehaviour
{
private LicenseSeatManager _manager;
void Start()
{
_manager = FindObjectOfType<LicenseSeatManager>();
// Subscribe to events
_manager.Client.Events.On(LicenseSeatEvents.LicenseValidated, _ =>
Debug.Log("License validated!"));
}
public void ActivateLicense(string licenseKey)
{
StartCoroutine(_manager.ActivateCoroutine(licenseKey, (license, error) =>
{
if (error != null)
{
Debug.LogError($"Failed: {error.Message}");
return;
}
Debug.Log($"Activated: {license.Key}");
}));
}
}
Unity SDK Features:
- Pure C# - No native DLLs, works everywhere
- IL2CPP Ready - Automatic link.xml injection
- WebGL Support - Uses UnityWebRequest
- Editor Tools - Settings window, inspectors
- Samples - Import from Package Manager
Godot Integration
using Godot;
using LicenseSeat;
public partial class LicenseManager : Node
{
private LicenseSeatClient _client;
public override void _Ready()
{
_client = new LicenseSeatClient(new LicenseSeatClientOptions
{
ApiKey = "pk_live_xxxxxxxx",
ProductSlug = "your-product"
});
}
public async void ValidateLicense(string licenseKey)
{
var result = await _client.ValidateAsync(licenseKey);
if (result.Valid)
GD.Print("License is valid!");
else
GD.Print($"Invalid: {result.Code}");
}
public override void _ExitTree() => _client?.Dispose();
}
Error Handling
try
{
var license = await client.ActivateAsync("INVALID-KEY");
}
catch (ApiException ex) when (ex.Code == "license_not_found")
{
Console.WriteLine("License key not found");
}
catch (ApiException ex) when (ex.Code == "seat_limit_exceeded")
{
Console.WriteLine($"All {ex.Details?["seat_limit"]} seats are in use");
}
catch (ApiException ex)
{
Console.WriteLine($"API Error: {ex.Code} - {ex.Message}");
Console.WriteLine($"Status: {ex.StatusCode}");
Console.WriteLine($"Retryable: {ex.IsRetryable}");
}
Common Error Codes
license_not_found- Invalid license keylicense_expired- License has expiredlicense_suspended- License is suspendedseat_limit_exceeded- All seats are in usedevice_not_activated- Device not activated for this licenseinvalid_api_key- Invalid API key
API Reference
Client Methods
| Method | Description |
|---|---|
ActivateAsync(licenseKey) |
Activate a license on this device |
ValidateAsync(licenseKey) |
Validate a license (check if valid) |
DeactivateAsync() |
Deactivate the current license |
HasEntitlement(key) |
Check if an entitlement is active |
CheckEntitlement(key) |
Get detailed entitlement status |
GetStatus() |
Get current license status |
GetCurrentLicense() |
Get the cached license |
TestAuthAsync() |
Test API connectivity |
ValidationResult Properties
| Property | Type | Description |
|---|---|---|
Valid |
bool |
Whether the license is valid |
Code |
string? |
Error code if invalid |
Message |
string? |
Error message if invalid |
Offline |
bool |
True if validated offline |
License |
License? |
License data |
ActiveEntitlements |
List<Entitlement>? |
Active entitlements |
License Properties
| Property | Type | Description |
|---|---|---|
Key |
string |
The license key |
Status |
string? |
License status (active, expired, etc.) |
ExpiresAt |
DateTimeOffset? |
When the license expires |
PlanKey |
string? |
Associated plan |
SeatLimit |
int? |
Maximum allowed seats |
ActiveSeats |
int |
Currently used seats |
ActiveEntitlements |
List<Entitlement>? |
Active entitlements |
Platform Support
| Platform | Package | Install |
|---|---|---|
| .NET (Console, ASP.NET, WPF, MAUI) | NuGet | dotnet add package LicenseSeat |
| Godot 4 | NuGet | dotnet add package LicenseSeat |
| Unity | UPM | See Unity section |
Next Steps
- C++ SDK - For native applications
- JavaScript SDK - For web applications
- Offline Licensing - Air-gapped validation
- API Reference - Direct API access