Documentation Reference Updated

The update and license API

The endpoints Keyward Desktop and the command line themselves talk to, for people who run a mirror, automate a deployment or want to know exactly what is sent.

This is the API of this site: licenses, entitlements, the update channels and staff sign-in. Keyward Server's own API (projects, secrets, machine identities) is upstream's, documented with the server. The Keyward MCP's tools are described under AI sessions.

Conventions

  • The API is under /api/v1, over HTTPS only. Every answer is JSON, except the installer itself.
  • An installation proves its entitlement with Authorization: Bearer <entitlement>. Cookies are not read by the API.
  • One entitlement covers both products; each product reads its own update channel.
  • A refusal has this shape, with a status code that matches:
{ "ok": false, "error": "seat_limit", "message": "All 3 seat(s) of this license are in use (…).", "ref": "9f2c41aa" }

error is stable and meant for programs. message is meant for people. ref, when present, is the reference of the line in the site's audit trail.

  • Requests are limited per network address. Over the limit, the answer is 429 with a Retry-After header.

An installation describes itself

Several requests carry a device:

{ "hash": "…43 characters…", "name": "OPS-LAPTOP-7", "platform": "win-x64", "version": "1.0.0", "product": "keyward" }

hash is the SHA-256, in base64url, of the text keyward-device: followed by an identifier that the program makes at random when it is first run. The identifier itself never leaves the computer, and is not derived from its hardware. product is keyward (Keyward Desktop) or keyward-cli (the command line): which program asked. The two programs on one computer share one device identifier, so they share one activation and one seat; product records the one that asked last.

Licenses and entitlements

POST /api/v1/licenses/activate

{ "key": "KW-XXXXX-XXXXX-XXXXX-XXXXX-XXXXX", "device": { … } }

Activates the installation: a new seat, or the seat the installation already has. Answers:

{
  "ok": true,
  "token": "eyJhbGciOiJFUzI1NiIs…",
  "entitlement": {
    "id": "act_…", "kind": "license", "licensee": "…", "organization": "…",
    "plan": "early-access", "planTitle": "Early access", "channels": ["stable"],
    "issued": "2026-10-15T08:00:00+00:00", "expires": "2026-11-14T08:00:00+00:00",
    "seats": { "used": 1, "total": 3 }
  }
}
error Status Meaning
license_unknown 403 The key is not known, or is mistyped.
license_revoked 403
license_expired 403
seat_limit 409 Every seat is in use. The message names the installations.
licensing_unavailable 503 The site has no signing key configured.

GET /api/v1/entitlements/current

With the bearer token. Says what the entitlement is today, from the site's records.

POST /api/v1/entitlements/refresh

With the bearer token, and { "device": { … } }. Answers like activate, with a new token. An expired token cannot be refreshed: activate again.

POST /api/v1/entitlements/deactivate

With the bearer token. Gives the seat back. The token stops working at once.

error Status Meaning
entitlement_expired 401 Activate again.
entitlement_invalid 401 Not a token this site signed, or not for this site.
entitlement_revoked 401 The installation was deactivated.

The entitlement token

A JWS in compact form, signed with ES256. Its header has typ kw-ent+jwt and the kid of the signing key. Its claims:

Claim Meaning
iss https://keyward.exprezoe.com
aud keyward (one audience for both products)
sub The activation.
jti This token.
iat, nbf, exp Issued, not valid before, expires.
kind license or staff
lic, name, org, plan The license, the licensee, the organisation, the plan.
chn The release channels.
dev The installation's hash.

Each program checks the signature by itself against the license key compiled into it. The key was generated inside a vault and has never been anywhere else; its public half:

Key Public key (SubjectPublicKeyInfo, base64)
keyward-license-2026-10 MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEgGcvGlhcvB0PHqnXs9JRbYHRPR6ppNMqc7P2lA5KBwpFS7UIZNxmVIsBdRv58vK31FxB4UAfSLI4jIkl5iW0eg==

The update channels

GET /api/v1/updates/{product}/{channel}/{platform}/keyward-update.json
GET /api/v1/updates/{product}/{channel}/{platform}/keyward-update.json.sig
GET /api/v1/updates/{product}/{channel}/{platform}/{installer}

With the bearer token. product is keyward or keyward-cli; channel is stable or preview; platform is win-x64.

The manifest is served byte for byte as it was signed. It names its installer by file name only, so the installer is read from beside the manifest, and a mirror can serve a release as it is. Both small files carry an ETag; the installer supports ranges, so an interrupted download can be resumed.

error Status Meaning
channel_not_allowed 403 The entitlement does not include that channel.
no_release 404 Nothing has been released for that product on that channel.

GET /api/v1/releases[?product=…]

With the bearer token. Every release the entitlement includes, of both products or of one, newest first.

Staff sign-in

For people at Exprezoe, in place of a license key.

  1. GET /api/v1/auth/identity says whether staff sign-in is on, names the issuer and the client to sign in with, and says how recent the sign-in at the issuer must be (maxAge, in seconds: the program sends it as max_age).
  2. POST /api/v1/auth/identity/challenge with { "device": { … } } answers { "nonce": "…", "expires": "…" }.
  3. The program signs in at the issuer in the system browser (authorization code with PKCE), with that nonce.
  4. POST /api/v1/auth/identity/exchange with { "id_token": "…", "device": { … } } answers like activate.

The site accepts an ID token only when its nonce is a challenge the site issued to that installation and has not seen used. It then checks the signature against the issuer's published keys (RS256 only), the issuer, the audience, the lifetime, that the token is fresh, that the sign-in at the issuer is no older than maxAge (auth_time), that a second factor was used, and that the person is in a group that may use the programs.

error Status Meaning
identity_disabled 503 Staff sign-in is not switched on.
challenge_unknown 401 The sign-in was not started with this site, or took longer than ten minutes.
token_replayed 409 That sign-in was already used.
token_invalid 401 The ID token could not be verified.
stale_authentication 401 The sign-in at the issuer is older than maxAge, or the token does not say when it was made.
mfa_required 403 No second factor was used.
not_in_required_group 403
issuer_unavailable 503 The issuer's keys could not be read.

What the site is

GET /api/v1/health answers { "ok": true } when the site and its records are reachable. GET /api/v1/meta names the products, the site's version and which of the above are switched on.