Licencly 1.0.1

dotnet add package Licencly --version 1.0.1
                    
NuGet\Install-Package Licencly -Version 1.0.1
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Licencly" Version="1.0.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Licencly" Version="1.0.1" />
                    
Directory.Packages.props
<PackageReference Include="Licencly" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Licencly --version 1.0.1
                    
#r "nuget: Licencly, 1.0.1"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Licencly@1.0.1
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Licencly&version=1.0.1
                    
Install as a Cake Addin
#tool nuget:?package=Licencly&version=1.0.1
                    
Install as a Cake Tool

Licencly for .NET

Verify Licencly licenses and check for entitled updates, from .NET.

dotnet add package Licencly

Targets net8.0 and netstandard2.0, the latter deliberately, because a great many Windows desktop ISVs are still on .NET Framework 4.6.1+ with a codebase they are not going to port to run a licensing check.

The idea

The signed license file is the answer; the network is an optimisation. The client reads its cache, refreshes when due, and keeps working through an outage until the grace period is spent, so Licencly being unreachable never stops software you have already sold.

Quickstart

Copy the product UUID and public key from your dashboard and embed them at build time. Fetching keys at runtime would defeat the whole scheme.

using Licencly;

var client = new LicenclyClient(new LicenclyOptions
{
    ProductUuid = "fec65576-…",
    // Products → your product → Signing key.
    PublicKeys = new Dictionary<string, string>
    {
        ["9f2c1a44-…"] = "MWvD7YE6HjI/DQ0kYGJFNG4kXlx4hP6ck1Vr4j77fzk=",
    },
    Fingerprint = MachineId(), // yours; see below
});

var decision = await client.ValidateAsync(userEnteredKey);

switch (decision.Outcome)
{
    case Outcome.Valid:
        break; // run
    case Outcome.NotActive:
        Show("This license has been suspended or revoked.");
        break;
    case Outcome.Expired:
        Show("This license expired. Renew to continue.");
        break;
    case Outcome.WrongMachine:
        Show("This license is in use on another machine.");
        break;
    case Outcome.Stale:
        Show("Please connect to the internet to re-check your license.");
        break;
    case Outcome.Invalid:
        Show("This license file could not be verified.");
        break;
}

ValidateAsync makes no network call at all while the cached file is still fresh.

Offline

When Behaviour
Before rev Cache only, no network
Between rev and rev + grace Keeps working, refreshes in the background. NeedsRevalidation is true
After rev + grace Outcome.Stale

A LicenclyNetworkException inside the grace window is not an error your users should see. The cached decision is returned instead, and you only see the exception when there is no cache at all.

Where the cache lives

%APPDATA%\licencly\, not next to your executable. An application installed in Program Files cannot write beside itself without elevation, and a licensing check that needs admin rights will not have them when it matters.

Updates

var result = await client.CheckForUpdateAsync(key,
    currentVersion: "1.2.0", platform: "windows", arch: "x64");

if (result.Available)
{
    var path = await client.DownloadArtifactAsync(key, result.Release!, tempDir, artifactPublicKey);
}
else if (result.RenewalWouldUnlock)
{
    // Not an error: a newer version exists and this license is not entitled to
    // it. result.Latest names what renewing would unlock.
    Show($"Version {result.Latest!.Version} is available with an active plan.");
}

Checking for updates never consumes a seat.

Verifying downloads

artifactPublicKey is your own Ed25519 public key, compiled into your application, not fetched from Licencly. Licencly stores and serves the signature but cannot produce one, so a compromise of Licencly cannot push code to your users. DownloadArtifactAsync verifies the digest and that signature before the file is moved into place; passing null reduces it to corruption detection.

Machine fingerprints

The SDK does not compute one, because a good fingerprint is specific to what you ship. It must stay stable across restarts, app updates and reboots, and survive minor hardware change. On Windows, MachineGuid and a volume serial are common starting points; both have failure modes worth reading about. VMs, containers and cloned disks defeat naive approaches.

Leaving Fingerprint empty disables machine binding, and a license file copied to another machine will still verify.

Clock tampering

Expiry is checked against a clock the user controls; rolling it back extends an expired license offline. This is unavoidable for anything that must work without a network.

The SDK records the furthest-forward time it has seen and rejects a jump backwards of more than 24 hours. That is a speed bump, not a fix.

Errors worth telling apart

Type Meaning
LicenclyNetworkException Could not reach the server. Retryable
LicenseFileException Signature or format failure. Never retry
LicenclyApiException.SeatLimitReached No free activations
LicenclyApiException.NotFound Unknown product or key
LicenclyApiException.RateLimited Carries RetryAfter

Dependencies

BouncyCastle.Cryptography, because .NET has no Ed25519 in the base class library on any target this package supports. The alternative is implementing field arithmetic by hand, which is the wrong answer for signature verification.

Conformance

dotnet test

Runs data/vectors.json, the same suite every Licencly SDK runs. If this SDK ever disagrees with the Go, TypeScript or Python ones, that test fails first.

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.1 110 9/8/2026
1.0.0 105 9/6/2026