Skip to content

.NET SDK — activate a license

Activation exchanges a license key (and the device’s fingerprint) for a session — a claimed seat plus a signed, cached license the SDK can validate locally. Your application holds that session while it runs and releases it on shutdown.

ILicenseSession is the single entry point. Resolve it from the request/lifetime scope and call AccessLicenseAsync. The first call activates; subsequent calls return the cached, still-valid license without a round trip.

public class LicenseGate(ILicenseSession session)
{
public async Task<bool> IsLicensedAsync()
{
var license = await session.AccessLicenseAsync();
return license is { LicenseValidation.IsOperational: true };
}
}

AccessLicenseAsync returns null when no valid license can be obtained (for example, the key is unknown or activation was refused). It never throws for the ordinary “not licensed” case — check for null and for IsOperational.

A null license tells you that activation failed, not why. session.LastError carries the failure detail from the most recent attempt — a revoked or unknown key, a refused activation, a network error — and is null again after a success:

var license = await session.AccessLicenseAsync();
if (license is null)
{
ShowActivationError(session.LastError?.ErrorMessage ?? "Unknown error");
}

Use it to show the user something actionable instead of a generic “not licensed”.

license.LicenseValidation describes the license without you having to interpret raw dates:

Property Tells you
IsOperational The license currently permits protected use (active, in trial, or within grace). Gate on this.
LicenseStatus Active, GracePeriod, Expired, or Invalid.
LicenseModel Trial, Perpetual, or Subscription.
TrialStatus InTrial, TrialExpired, or NotInTrial.
LeaseStatus The offline-freshness signal: Fresh, Stale, StaleLockout, or Unverifiable — how long since the license was last confirmed against the server, and whether the allowed offline window has run out.
CurrentSession The session id — pass it when metering consumption.

Gate features on IsOperational rather than on LicenseStatus == Active: it already accounts for trials and the grace window, so a brief backend outage or a legitimate trial doesn’t lock out a paying customer.

The SDK refreshes the license in the background on the interval you configure (LicenseRefreshIntervalSeconds). To force a refresh — for instance right after a plan change — call RefreshLicenseAsync:

await session.RefreshLicenseAsync();

When the application shuts down, or a user signs out, release the session so the seat is freed and the final usage is flushed:

await session.ReleaseSessionAsync();

In a host-based app the SDK flushes pending usage on shutdown for you; call ReleaseSessionAsync explicitly when you end a session earlier than process exit.

When your application has a signed-in user, you can activate against the entitlements assigned to that user instead of distributing a license key. On the fluent builder, call UseInteractiveUserActivation(); the request then carries the user’s token, and the activation code becomes optional when the user has exactly one assigned entitlement. See authentication for the wire contract and the end-user portal for how users see what’s assigned to them.

Entitlements whose activation policy requires identity verification hold the activation until the user confirms a link sent by email. Supply the address with UseActivationEmail(...) on the fluent builder; the server emails a one-time confirmation link and keeps the activation pending (HTTP 409 operation.pending) until it is clicked, after which the same activation call succeeds. Entitlements without that policy ignore the address.

For an offer open to visitors, UseAnonymousTry(tryCode) on the fluent builder activates without an account at all. The server answers with this device’s own short-lived license, issuing one on first contact and returning the same one while it lasts, so a returning visitor finds the allowance where they left it.

using Revenusion.MonetizeIt.HttpConnector;
using Revenusion.MonetizeIt.Client.AspNetCore;
var client = MonetizeItClientFactory.Create(
$"https://{tenant}.{host}", new AnonymousAuthentication());
var session = new LicenseClientBuilder()
.UseAnonymousTry("your-public-try-code")
.UseNodeId(StaticNodeId.Create(deviceId))
.UsePublicKey(base64PublicKey)
.UseMonetizeItHttpClient(client)
.BuildSession();

A fingerprint is required — supply one with UseNodeId(...). Every builder chain also needs the pinned provider key: without UsePublicKey(...), BuildSession() throws while AllowUnsignedLicenses is at its default false (the provider key is mandatory). The try code is public, so it names the offer and never the caller; a request that identifies no device is refused. When the offer’s issuance limits are reached the activation is refused with HTTP 429 and the detail lands in LastError; tell the visitor to try again later rather than to sign up.

The license behaves like any other: features, quotas and expiry are the platform’s answers. Two things differ. The plan an offer issues try licenses on usually denies past its allowance, so a refusal is the end of the try and the moment to invite a sign-up. And the license carries a try claim, so an application that reads its own token can tell the two apart. Changing plan and topping up credits both answer with an invitation to sign up.

Each activation claims one seat against the entitlement. The SDK identifies the device with a fingerprint; a stable fingerprint means the same install reuses its seat across restarts instead of consuming a new one. If the entitlement is out of seats, activation is refused and AccessLicenseAsync returns null, with the refusal detail in LastError — surface that to the user as “no seats available” rather than a generic error.