Offline certificates

A certificate is a signed snapshot of a license that your software can verify without network access. It is signed with the product signing key (not the platform key), so each product embeds its own public key.

Fetching

GET /api/v1/licenses/{key}/certificate?fingerprint=sha256:…&ttl=2592000
GET /api/v1/licenses/{key}/certificate?fingerprint=sha256:…&format=file   → downloadable .lic

The license must currently be valid for the given fingerprint (the machine must be activated when the policy requires fingerprints). The certificate expires at the earlier of ttl (default 30 days, max 1 year) and the license expiry.

Format

{ "format": "softlicense/v1", "alg": "ed25519", "kid": "key_…", "enc": "<base64 JSON payload>", "sig": "<base64 signature over the raw payload bytes>" }

payload = { "issued_at", "expires_at", "fingerprint", "product": {...}, "license": { "key", "status", "expires_at", "entitlements", ... }, "policy": {...}, "activations": [...] }

Verifying

  1. Base64-decode enc to get the raw payload bytes.
  2. Verify sig over those bytes with the product public key whose id matches kid (GET /api/v1/products/{id}/public-key lists active and retired keys so rotation never breaks old files).
  3. Parse the payload. Reject if expires_at has passed or fingerprint does not match this machine.
  4. Use license.entitlements exactly as you would from the online API.
// Node.js
import { createPublicKey, verify } from "node:crypto";
const raw = Buffer.from(cert.enc, "base64");
const ok = verify(null, raw, createPublicKey(PRODUCT_PUBLIC_KEY_PEM), Buffer.from(cert.sig, "base64"));
const payload = JSON.parse(raw.toString("utf8"));

The .lic file is the same JSON envelope, base64 encoded between -----BEGIN SOFTLICENSE LICENSE----- markers.