Unity SDK

Official SDKs

Unity SDK

Unity 2021.2+ client (.NET Standard 2.1 API Compatibility Level), zero external package dependencies — no Newtonsoft.Json, no additional UPM packages. Works on Desktop, Mobile, and Console builds; WebGL works for online calls, with one crypto caveat noted below.

New to PermitCore? Follow the Unity software licensing quickstart to create a product, validate a real key in Unity, and publish that product in your built-in Store.
Download Unity SDK (ZIP)

Installation

Listed on OpenUPM (com.permitcore.sdk) — the simplest option if you have the openupm-cli installed:

openupm add com.permitcore.sdk

Or install directly from the tagged git repo — Unity Package Manager's git-URL install works with no manual setup: Window → Package Manager → + → Install package from git URL...

https://github.com/permitCore-spec/permitcore-sdk-unity.git#v1.1.0

Or work from the source ZIP above: extract it and in Unity: Window → Package Manager → + → Install package from disk... and select the extracted folder's package.json. Or copy Runtime/'s contents straight into your project's Assets/ folder.

Quick start — validate

using PermitCore;
using UnityEngine;

public class LicenseGate : MonoBehaviour
{
    private PermitCoreClient _client;

    async void Start()
    {
        _client = new PermitCoreClient("https://api.permitcore.dev");
        var result = await _client.ValidateAsync(
            "PERMIT-XXXX-XXXX-XXXX-XXXX",
            expectedProductId: "7f3e9a2b-1c4d-4e8f-9a6b-3d2c1e0f5a8b"); // optional — reject a key issued for a different product

        if (result.ErrorCode == "WrongProduct")
        {
            Debug.LogError("This key is for a different product: " + result.ProductId);
            return;
        }
        if (!result.IsValid)
        {
            Debug.LogError("License invalid: " + result.Message);
            return;
        }

        if (result.HasFeature("pro"))
            EnableProFeatures();
    }
}

Activate (call once per installation)

var result = await _client.ActivateAsync(
    "PERMIT-XXXX-XXXX-XXXX-XXXX",
    deviceId: null,                    // auto-generated when omitted
    deviceName: SystemInfo.deviceName,
    version: Application.version,   // optional — enforces min/maxVersion
    expectedProductId: "7f3e9a2b-1c4d-4e8f-9a6b-3d2c1e0f5a8b"); // optional

if (result.ErrorCode == "WrongProduct")
    Debug.LogError("Wrong product: " + result.ProductId);
else if (!result.IsValid)
    Debug.LogError("Activation failed: " + result.Message);

Metered billing

await _client.MeterAsync(licenseKey, "level_completed");

await _client.MeterAsync(licenseKey, "export", quantity: 5,
    meta: new Dictionary<string, object> { ["format"] = "png" });

Floating licenses

var session = await _client.CheckoutAsync(licenseKey);
if (!session.Success) { Debug.LogError("No seats available: " + session.Message); return; }

// Heartbeat every 4-5 minutes (e.g. from a coroutine or InvokeRepeating)
await _client.HeartbeatAsync(session.SessionToken);

// On quit / logout
await _client.CheckinAsync(session.SessionToken);

Offline license tokens

No extra package needed — System.Security.Cryptography.ECDsa is part of Unity's .NET Standard 2.1 surface on Desktop, Mobile, and Console targets.

// Pure local verification — no network call, never throws on Desktop/Mobile/Console.
var result = PermitCoreClient.VerifyOfflineToken(token, publicKeyBase64);
if (result.IsValid)
    Debug.Log("Valid! Product: " + result.Payload.ProductName);

// Bind to this device + persist locally (call once, e.g. at install time)
var activated = _client.ActivateOffline(token, publicKeyBase64, deviceId);

// On every later launch — no token needed, reads the local cache
var cached = _client.ValidateOffline(deviceId);
Not supported on WebGL builds specifically — the browser sandbox WebGL runs in has no System.Security.Cryptography implementation, so the three offline-token methods above will throw on that one platform. Online ValidateAsync/ActivateAsync work fine on WebGL via UnityWebRequest — only the fully-offline crypto path is affected, and that's a platform constraint of WebGL itself, not something this SDK can work around.

Hardware ID

// Default: a random id persisted to a local file — works identically on every platform.
string hwid = _client.GetHardwareId();

// Unity-idiomatic alternative, recommended on mobile/console:
string hwid = UnityHardwareId.Get(); // SHA-256 of SystemInfo.deviceUniqueIdentifier

LicenseResult reference

FieldTypeDescription
IsValidboolTrue if the license is active and valid
ProductNamestringProduct the license belongs to
RemainingActivationsint?Activation slots remaining
ExpiresAtstringISO 8601 expiry date, null = perpetual
FeaturesList<string>Feature flag list, e.g. ["export","api"]
IsTrialboolTrue for trial licenses
TrialDaysRemainingint?Days until trial expires
NodeLockedboolTrue if bound to a specific device
OfflineGraceDaysint?How many days the cache remains valid
MinVersion / MaxVersionstringVersion enforcement bounds
VendorWarningstringNon-fatal message from the vendor
MessagestringReason when IsValid == false
IsOfflineboolTrue when result came from local cache
ErrorCodestringStable, machine-readable failure reason
ProductIdstringStable ID of the product this license belongs to. Always present when a license was found, even without passing expectedProductId.

HasFeature(string feature) — case-insensitive feature check.

Product scoping: by default, any active key belonging to your tenant validates/activates successfully regardless of which product it was issued for — this is exactly the gap this SDK's own demo surfaced while testing it in a real Unity Editor. Both ValidateAsync/ActivateAsync take an optional trailing expectedProductId parameter — set it and the server rejects a mismatch with ErrorCode == "WrongProduct". Find a product's ID in the Admin panel under Products.

Try it live: the downloadable Task Manager Pro demo is a complete Unity project (attach one script, press Play — no Canvas/prefab setup) gated behind a real license, with a built-in developer console panel exercising every SDK call against your own PermitCore instance.