Docs

License keys

Sell access to your software with license keys. Each member who purchases gets a unique key; your software validates it against Subicon’s API to unlock or lock access.

#How it works

  • A member who purchases a product in your community automatically gets one license key for this app (shown under “Your license keys”).
  • You configure the downloads (one URL per platform) and, optionally, let members regenerate their key.
  • Your software sends the key to the validation endpoint and trusts its answer.

A member gets one key per purchased product that unlocks this app, so the same person may have several keys.

#Validation endpoint

A public, unauthenticated GET endpoint — the key itself is the credential. It is rate-limited per IP.

HTTP
GET https://subicon.io/api/software/validate?key=XXXX-XXXX-XXXX-XXXX

#Request

Pass the license key as the “key” query parameter (dashes optional, case-insensitive).

Shell
curl "https://subicon.io/api/software/validate?key=ABCD-EFGH-JKMN-PQRS"

#Response

JSON. The endpoint re-checks the member’s purchase live, so a refund or cancellation invalidates the key automatically.

JSON
{ "valid": true, "status": "active", "software": "Your community", "product": "Pro", "nonce": "n1", "ts": 1733520000, "signature": "..." }
statusMeaning
activeValid key, purchase still active → unlock.
expiredThe member no longer has an active purchase (refund, cancellation, expiry) → lock.
revokedThe key was revoked (e.g. regenerated by the member) → lock.
device_limitValid key, but this device exceeds the product’s activation limit → lock.
not_foundUnknown or malformed key → lock.

#Devices & activation limits

Send a stable `device` id. If the seller set a per-product device limit, a new device beyond the limit returns status `device_limit`.

#Verifying the signature

Every response is signed (Ed25519) with your app’s private key. Verify it with your app’s public key (found in the Software app settings) to be sure the response really comes from Subicon.

Signed message = `valid|status|key|nonce|ts` (pipe-joined). Send a random `nonce` each call and check it is echoed back to prevent replay.

#Integrating in your software

Subicon provides the key and this endpoint. It is up to your software to call it (at launch and/or periodically) and to allow or block access based on the response.

JavaScript
import { verify, createPublicKey } from 'crypto';

const nonce = crypto.randomUUID();
const url = 'https://subicon.io/api/software/validate'
  + '?key=' + encodeURIComponent(licenseKey)
  + '&device=' + encodeURIComponent(deviceId)   // a stable per-machine id
  + '&nonce=' + nonce;
const data = await (await fetch(url)).json();

// Verify the signature with your app's PUBLIC KEY (from the Software app settings).
const msg = `${data.valid}|${data.status}|${normalizedKey}|${data.nonce}|${data.ts}`;
const ok = data.signature && verify(null, Buffer.from(msg), createPublicKey(PUBLIC_KEY_PEM), Buffer.from(data.signature, 'base64url'));

if (ok && data.valid) startApp();
else showInvalidKey(data.status);

Tip: cache the result briefly and re-check on launch. Always verify the response signature (see “Verifying the signature”).