Skip to main content

Guides

Feature Gating

Control access to individual features using entitlements attached to licenses and policies.

How Entitlements Work

Entitlements are named features (like "export" or "api_access") that you create and attach to policies or individual licenses. During validation, you can require specific entitlements — if they are missing, the API returns ENTITLEMENTS_MISSING.

1. Create Entitlements

Define the features you want to gate. Each entitlement has a human-readable name and a machine-readable code.

create_entitlements.py
# Entitlements are a management-plane resource, not exposed on the SDK client
# — create them via the REST API (Management API key, entitlements:write scope).
import httpx

api_key = "lk_live_your_key_here"
headers = {"Authorization": f"Bearer {api_key}"}

def create_entitlement(code: str, name: str) -> str:
    resp = httpx.post(
        "https://www.licentric.com/api/v1/entitlements",
        headers=headers,
        json={"code": code, "name": name},
    )
    return resp.json()["data"]["id"]

# Create your product's entitlements once — reuse the returned ids below.
export_id = create_entitlement("export", "Export")
premium_analytics_id = create_entitlement("premium_analytics", "Premium Analytics")
api_access_id = create_entitlement("api_access", "API Access")

2. Attach to Policies or Licenses

Attach entitlements at the policy level (all licenses under that policy inherit them) or at the individual license level for fine-grained control.

attach.py
# Attach entitlements to a policy — every license under that policy inherits
# them. This REPLACES the policy's full entitlement set (not incremental).
httpx.patch(
    f"https://www.licentric.com/api/v1/policies/{policy_id}",
    headers=headers,
    json={"entitlementIds": [export_id, premium_analytics_id]},
)

# To grant a DIFFERENT set to one specific license, set entitlementIds when you
# CREATE that license — there is no attach-after-creation route for a single
# license (only the policy-level PATCH above can change entitlements post-hoc).
httpx.post(
    "https://www.licentric.com/api/v1/licenses",
    headers=headers,
    json={
        "productId": product_id,
        "policyId": policy_id,
        "entitlementIds": [export_id, premium_analytics_id, api_access_id],
    },
)
Policy-level vs license-level
Use policy-level entitlements for subscription tiers (e.g., all "Growth" licenses get analytics). Use license-level entitlements for one-off feature grants or custom enterprise agreements.

3. Validate with Entitlement Check

Pass the required entitlement codes to the validate call. The API checks the license is valid and that all required entitlements are present.

Python

validate.py
# Validate and check for specific entitlements
result = client.validate(
    key="DSK-XXXX-XXXX-XXXX-XXXX",
    entitlements=["export"]  # Require "export" entitlement
)

if result.valid:
    # License is valid AND has the "export" entitlement
    run_export()
elif result.code == "ENTITLEMENTS_MISSING":
    print("Upgrade to access the export feature.")
else:
    print(f"Validation failed: {result.code}")

TypeScript

validate.ts
const result = await client.validate({
  key: "DSK-XXXX-XXXX-XXXX-XXXX",
  entitlements: ["export"], // Require "export" entitlement
});

if (result.valid) {
  runExport();
} else if (result.code === "ENTITLEMENTS_MISSING") {
  showUpgradePrompt("Upgrade to access the export feature.");
}

4. Implement Feature Gates

Build a reusable feature gate function that wraps validation with an entitlement check. Use it throughout your application to conditionally enable features.

Python

feature_gate.py
def feature_gate(license_key: str, required_feature: str):
    """Gate a feature behind an entitlement check."""
    result = client.validate(key=license_key)

    if not result.valid:
        return False

    # Check entitlements from the validation response
    return required_feature in result.entitlements

# Usage in your application
if feature_gate(user.license_key, "premium_analytics"):
    show_analytics_dashboard()
else:
    show_upgrade_banner("Unlock analytics with a premium license")

TypeScript

feature-gate.ts
async function featureGate(
  licenseKey: string,
  requiredFeature: string
): Promise<boolean> {
  const result = await client.validate({ key: licenseKey });

  if (!result.valid) {
    return false;
  }

  return result.entitlements.includes(requiredFeature);
}

// Usage in your application
if (await featureGate(user.licenseKey, "premium_analytics")) {
  showAnalyticsDashboard();
} else {
  showUpgradeBanner();
}
Entitlements in offline mode
Offline license files include the full entitlements array in their payload. Feature gates work identically in offline mode — the SDK reads entitlements from the signed certificate.