Booting neural core...
Booting neural core...
License the software you sell. You add your products in the Portal and issue a license to each customer. Their installation exchanges a one-time activation code for a signed token, verifies that token offline, and checks in once a day so you can suspend, revoke or move the license whenever you need to.
@cybernethicc/license-sdk, wraps everything below. Ask support for access.| Plan | Price / month | Includes |
|---|---|---|
| Starter | Rp 50.000 | Up to 10 licenses, 1 product |
| Growth | Rp 250.000 | Up to 100 licenses, 5 products |
| Scale | Rp 500.000 | 500 active licenses included, then Rp 1.000 each; unlimited products; white-label and custom domains |
An active license is one whose installation checked in at least once during the month. Plans are billed monthly from your balance or by invoice; a plan change takes effect at the next billing date. If an invoice stays unpaid for 7 days, your licenses report suspended at their next check-in until it is paid.
acme-pos. It appears as product in every token.POST https://portal.cybernethicc.com/api/v1/licenses/activate
Content-Type: application/json
{
"activation_code": "CYB-XXXXX-XXXXX-XXXXX-XXXXX",
"instance_fingerprint": "a stable id of this machine",
"version": "1.4.0"
}{
"status": "active",
"license_token": "eyJhbGciOiJFZERTQSIs...",
"next_checkin_after": "2026-10-03T08:00:00Z"
}A code works once. Store the token; it is what your app runs on from now on.
The token is a JWT signed with EdDSA. Fetch our public keys once and cache them; the token header names the key in kid.
GET https://portal.cybernethicc.com/api/v1/licenses/jwksThen check, in this order:
vendor equals your vendor id. This stops a license issued by someone else from unlocking your app.bound_to equals this machine's fingerprint.exp is in the future. Past it, limit the app until the next successful check-in.import { verifyLicense, checkin } from "@cybernethicc/license-sdk"
const { claims, state } = await verifyLicense(token, {
fingerprint: machineId,
vendor: "YOUR-VENDOR-ID",
})
if (state === "expired") limitTheApp()
if (claims.modules.includes("reports")) enableReports()Sign the exact request body with the checkin_secret from the token: HMAC-SHA256 over <unix seconds>.<body>, hex encoded. The timestamp must be within 5 minutes of our clock.
POST https://portal.cybernethicc.com/api/v1/licenses/checkin
Content-Type: application/json
X-License-Signature: t=1759392000,v1=<hex hmac>
{
"license_id": "<sub from the token>",
"instance_fingerprint": "a stable id of this machine",
"version": "1.4.0",
"token_version": 3
}{
"status": "active",
"token_version": 3,
"entitlements_changed": false,
"license_token": "eyJhbGciOiJFZERTQSIs...",
"next_checkin_after": "2026-10-04T08:00:00Z"
}status is active, suspended, expired or revoked. Always replace the stored token with the one returned.
| Claim | Meaning |
|---|---|
| sub | License id (send it as license_id at check-in) |
| vendor | Your vendor id |
| product | Your product id |
| customer | The customer name you entered |
| edition | Edition of the license |
| modules | Array of module names the customer may use |
| limits | Object of numeric limits (seats, outlets, anything you define) |
| white_label | May the installation replace your branding (Scale) |
| custom_domains | Extra hostnames the installation may serve (Scale) |
| perpetual | True for a perpetual license |
| bound_to | Machine fingerprint the license is bound to |
| exp | Expiry; renewed by every successful check-in |
| token_version | Bumps whenever you change, suspend or reissue the license |
| checkin_url, checkin_secret | Where and how to check in |
| Status | When |
|---|---|
| 400 | The body is missing a field or is not valid JSON |
| 401 | Unknown or already used activation code, unknown license, missing or bad signature |
| 403 | Activation of a license that is suspended, expired or revoked |
| 409 | The license is bound to another machine (status fingerprint_mismatch) |
Errors carry a JSON body with a message. Need help integrating? Talk to us.