DOCS LLMs

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)

  1. Open Window > Package Manager
  2. Click + > Add package from git URL...
  3. 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 (exp timestamp)
  • 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 key
  • license_expired - License has expired
  • license_suspended - License is suspended
  • seat_limit_exceeded - All seats are in use
  • device_not_activated - Device not activated for this license
  • invalid_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