Skip to content
Oclavex is in private preview, available to selected users. Public signup is blocked. Request access at [email protected].

.NET SDK — enforce entitlements

Once you hold a session, enforcing entitlements is a local check against the signed license — no network call on the hot path. license.FeatureValidation answers “is this feature licensed right now?” and “is this amount within the licensed limit?”.

var license = (await session.AccessLicenseAsync()).Value;
if (license is null || !license.FeatureValidation.IsValidFeature("advanced-export"))
{
return Results.Forbid(); // not licensed for this feature
}

IsValidFeature returns true only when the feature is present in the license and the license is operational — an expired license fails every feature check, so you don’t have to combine the two yourself. It accepts a feature code, or an ActivatedFeatureDto from LicensedFeatures.

To drive UI — show which capabilities are on, grey out the rest — read the licensed features directly:

foreach (var feature in license.FeatureValidation.LicensedFeatures)
{
// feature.FeatureCode, feature.Name, feature.Units, and its enablement flags
}

GetLicenseFeature(code) returns a single feature (or null) when you need its detail. Units is what the value is counted in, such as GB or seats, as you set it on the feature in the portal, so you can show “Storage: 50 GB” without hardcoding the unit. It is null for a true/false feature.

Each meter’s unit arrives the same way, keyed by the metric name its allowance uses:

foreach (var meter in license.Meters)
{
if (license.LicenseValidation.GetUsageLimit(meter.MetricName) is { } allowance)
{
// show allowance with meter.Unit, such as "500 renders"
}
}

A meter with no maximum has no allowance to show.

Units are labels for display. They aren’t signed, so never use them to convert or check a value.

Read the licensed products and their properties

Section titled “Read the licensed products and their properties”

The license also lists the products it covers, each with the custom properties you marked Public on the product in the portal — a support tier, a download URL, a branding value, anything your application wants to read at runtime without shipping it in the binary. A property is Private until you mark it Public, and a Private one never reaches the application:

foreach (var product in license.Products)
{
// product.ProductCode, product.ProductVersion, product.Name
foreach (var (key, property) in product.PropertyValues)
{
// property.Value, and property.Metadata for the entry's own key/value details
}
}

These properties are display and configuration metadata that arrive with the license and are refreshed whenever the license is renewed. They are not part of the signed grant, so gate features with IsValidFeature, never on a product property.

Each product’s code and version are also in the signed license. Read them from LicenseValidation when a build checks which version its license covers, for example a 1.x license running a 2.0 build:

foreach (var product in license.LicenseValidation.LicensedProducts)
{
// product.ProductCode and product.ProductVersion, as signed
}

Show the license terms and your support details

Section titled “Show the license terms and your support details”

The license carries the entitlement’s description and the link to the license terms (EULA) you set on the offer or the entitlement. Both are in license.Entitlement:

if (license.Entitlement.LicenseTermsUrl is { } termsUrl)
{
// show a "License terms" link to termsUrl
}

LicenseTermsUrl is null when no terms link is set. The application gets the link as it stands when the license is issued or refreshed, so a changed link reaches it at the next refresh. An offline device shows the link, not the terms themselves.

Details that describe your product rather than one customer’s deal, such as a support address, a support page or a copyright line, belong in the product’s custom properties. Mark each one Public so it reaches your application. These keys are a convention, not reserved names; your application reads whichever keys you choose:

Key Example value
support.url https://example.com/support
support.email [email protected]
copyright © 2026 Example Ltd
foreach (var product in license.Products)
{
if (product.PropertyValues.TryGetValue("support.email", out var supportEmail))
{
// show supportEmail.Value as the contact for this product
}
}

Neither the terms link nor the product properties are signed. Show them, but don’t make licensing decisions on them. What reaches your application lists what is signed and what isn’t.

For features that carry a numeric limit, ValidateUsageQuota checks a requested amount against the limit value licensed for the feature — “is a batch of 50 within what this license allows?”:

if (!license.FeatureValidation.ValidateUsageQuota("export.batch-size", 50))
{
return Results.Forbid(); // over the licensed limit
}

This is a local read of the license’s limit value; it does not track what has already been consumed. A quota that draws down with use — API calls, credits — is the metered path in report usage, which is authoritative and settles concurrent draw-down on the server.

A feature on an entitlement can have its own end date, the Expires date on the entitlement’s feature. After that date IsValidFeature returns false for the feature and ValidateUsageQuota refuses its limit, while the rest of the license keeps working. The SDK checks the date on the device at every call, so this also holds for a license issued before the date and for a device that is offline. A trial or a grace window doesn’t extend it.

The feature is still listed in LicensedFeatures, with its end date in FeatureExpiration, so you can show what ended and when.

Because IsValidFeature is based on IsOperational, features stay available during a valid trial and during the grace window after expiry. When the trial or grace ends, the same checks start returning false with no code change on your side. Read license.LicenseValidation.TrialStatus if you want to show a “trial ends in N days” banner.