XCAICX docs Product Contact

xcaicxctl CLI

The operator CLI. Key generation, offline minting, token inspection, and every admin operation against a running authority.

bash
xcaicxctl [--server URL] [--admin-key KEY] <command> [options]
Global flagDefaultNotes
--server$XCAICX_SERVER, else http://127.0.0.1:8000The licensing authority
--admin-key$XCAICX_ADMIN_KEYRequired for every server-side command

Set both in your environment and they disappear from your command lines:

bash
export XCAICX_SERVER=https://licensing.xcaicx.com
export XCAICX_ADMIN_KEY="$(security find-generic-password -a admin-key -s xcaicx-licensing -w)"

Commands split into two groups: offline (keygen, mint, inspect, catalogue) which need only the key file, and server (everything else) which need --admin-key.


Offline commands#

keygen#

bash
xcaicxctl keygen --out server/keys [--force]

Generates the root Ed25519 signing keypair. Writes the private key mode 600 and refuses to overwrite an existing key without --force.

Do not

Run this once, ever, and back the private key up offline before you issue a single licence against it. It is the root of trust for every licence you will ever issue; if it leaks, anyone can mint licences for your SDK and the only remedy is shipping new firmware with a new compiled-in public key. See Security.

The public half goes into core/src/license/root_key.inc and is compiled into the SDK.

mint#

Signs a licence offline, without contacting a server. This is the air-gapped path.

bash
xcaicxctl mint --sku edge-industrial \
               --customer CUST-PLANT7 \
               --device 3f2a9c4e8b1d5a6f \
               --days 365 \
               --key server/keys/root_ed25519.key \
               -o unit.token
FlagDefaultNotes
--skurequiredCatalogue code
--customerrequiredCustomer id
--device*Fingerprint to bind to. * is unbound.
--daysSKU defaultTerm.
--grace-daysSKU defaultDays past expiry that still run
--api-quota0Hard on-device inference cap; 0 = unmetered
--max-streamsSKU defaultOverride the stream cap
--modulesSKU setComma list, to restrict below the SKU
--license-idgeneratedSupply your own id
--require-activationoffForces the online per-unit exchange
--keyserver/keys/root_ed25519.keySigning key file
-ostdoutOutput file

Careful

mint writes no record to the licensing database. Seat accounting for minted licences is whatever you track yourself — that is the trade the air-gapped path makes. Do not mix mint and batch activation for the same customer without a plan for reconciling counts.

inspect#

Decodes a token and optionally verifies its signature.

bash
xcaicxctl inspect unit.token --pubkey server/keys/root_ed25519.pub
json
{
  "lic": "LIC-D3ACF708DB6048AB",
  "sku": "oem-industrial",
  "dev": "b2cd209a6826bd8b33c0fdaad6304106",
  "ent": {"detect": true, "defect": true, "ppe": true, "anpr": false},
  "lim": {"max_streams": 8, "max_fps": 30, "api_calls": 0},
  "exp": 0, "grace_days": 30, "act": "optional"
}

Without --pubkey it decodes but does not verify. That is useful for reading a token a customer emailed you, and it is not a validity check — say so out loud when someone pastes inspect output as evidence that a licence is good.

--pubkey accepts either the key string or a path to a file.

catalogue#

bash
xcaicxctl catalogue [--json]

Lists SKUs with modules, caps, terms, allowances and price tiers from the active catalogue, including any XCAICX_PRICING_JSON overrides.


Server commands#

customer#

bash
xcaicxctl customer "CamCo" --kind oem --contact [email protected]

--kind is oem or end_user. Prints the new CUST-… id.

batch#

Issues an OEM batch key good for N activations.

bash
xcaicxctl batch --customer CUST-CAMCO --sku oem-industrial --units 5000 -o batch.token
FlagNotes
--customer, --sku, --unitsRequired
--term-daysOverrides the SKU term
-oWrite the batch token to a file

The batch token is what goes onto the factory provisioning line. Treat the file as a credential: anyone holding it can consume units from the batch.

batch-status#

bash
xcaicxctl batch-status B-2026-1C4417D5

Purchased vs activated vs remaining. The first thing to check when an OEM says activation is failing — a 402 means the batch is simply spent.

license#

Issues a single licence through the server, recording it in the database.

bash
xcaicxctl license --customer CUST-PLANT7 --sku edge-industrial \
                  --device 3f2a9c4e8b1d5a6f --days 365
FlagDefault
--device*
--daysSKU term
--api-quota0
--require-activationoff

Prefer this over mint whenever the server is reachable: it leaves a record, so the licence shows up in fleet views and invoices.

revoke#

bash
xcaicxctl revoke LIC-D3ACF708DB6048AB --reason chargeback

Immediate for usage reporting; effective on the camera once it fetches /v1/revocations.

fleet#

bash
xcaicxctl fleet [--json]

Every activated unit, most recent first. Weakly-bound units are flagged.

Note

Scan the WEAK-BINDING column periodically rather than only when investigating a problem. A cluster of weakly-bound units on one customer means their integrator is deriving fingerprints from MAC addresses, which is a conversation to have before it becomes a cloning case.

usage#

bash
xcaicxctl usage LIC-D3ACF708DB6048AB

Totals for one licence: inferences, frames, stream-seconds, events, and the number of records received.

invoice#

bash
xcaicxctl invoice CUST-CAMCO --days 30 [--json]

Rates the period. --days 365 additionally includes annual maintenance on perpetual SKUs.


Recipes#

Stand up a new OEM programme

bash
CUST=$(xcaicxctl customer "CamCo" --kind oem | awk '{print $NF}')
xcaicxctl batch --customer "$CUST" --sku oem-industrial --units 5000 -o batch.token
xcaicxctl inspect batch.token --pubkey server/keys/root_ed25519.pub

Check a camera's licence against what you issued

bash
scp camera:/var/lib/xcaicx/unit.token .
xcaicxctl inspect unit.token --pubkey server/keys/root_ed25519.pub
xcaicxctl usage "$(python3 -c 'import json,sys;print(json.load(sys.stdin)["lic"])' < decoded.json)"

Reconcile a disputed invoice

bash
xcaicxctl batch-status B-2026-1C4417D5    # are more units activated than expected?
xcaicxctl fleet --json | python3 -m json.tool | grep -c weak_binding
xcaicxctl invoice CUST-CAMCO --days 30 --json

Verify a deployment did not break signing

bash
curl -s https://licensing.xcaicx.com/healthz | python3 -m json.tool
# public_key must equal the key compiled into the shipped SDK

Next#

Commercial software. Use requires a valid XCAICX licence token. Questions an integrator cannot answer from this page belong in an email to [email protected] — and, usually, in a fix to this page.

© 2026 AZMX AI · xcaicx.com