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.
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).
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.
{ "valid": true, "status": "active", "software": "Your community", "product": "Pro", "nonce": "n1", "ts": 1733520000, "signature": "..." }| status | Meaning |
|---|---|
active | Valid key, purchase still active → unlock. |
expired | The member no longer has an active purchase (refund, cancellation, expiry) → lock. |
revoked | The key was revoked (e.g. regenerated by the member) → lock. |
device_limit | Valid key, but this device exceeds the product’s activation limit → lock. |
not_found | Unknown 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.
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”).