Reference

Client API reference

The three public endpoints your app calls to activate, validate and deactivate a license. No secret needed.

These are the endpoints the SDKs call. They need no secret: the product ID is public and the license key identifies the customer. Use them directly if there is no SDK for your stack.

  • Base URL: https://api.keyrail.tech/v1 (configurable in every SDK).
  • JSON request and response bodies, Content-Type: application/json.
  • CORS is open on these routes.
  • fingerprint is the 64-character lowercase hex machine fingerprint.

Activate#

POST /v1/licenses/activate

json
{
  "product": "prd_7k2m9q4x1c8d3f6h0j5n",
  "key": "KR-7K2M9-Q4X1C-8D3F6-H0J5N",
  "fingerprint": "7a1acf765768ebbc09bfbbac0878d5e729d655a4be4db7510d2188f630881134",
  "name": "DESKTOP-42",
  "platform": "windows",
  "appVersion": "1.4.2"
}

name, platform and appVersion are optional. Response 200:

json
{ "certificate": "KR1.eyJ2IjoxLCJraWQiOiJrMSIs….1qOAhxQWB0OO…", "activation": "act_9c4h7k1m5p8r2t6v0x3z" }

Idempotent: activating a fingerprint that is already activated refreshes it and does not use another seat.

bash
curl https://api.keyrail.tech/v1/licenses/activate \
  -H "Content-Type: application/json" \
  -d '{"product":"prd_7k2m9q4x1c8d3f6h0j5n","key":"KR-7K2M9-Q4X1C-8D3F6-H0J5N","fingerprint":"7a1acf765768ebbc09bfbbac0878d5e729d655a4be4db7510d2188f630881134"}'

Validate#

POST /v1/licenses/validate

Same body as activate, without name:

json
{
  "product": "prd_7k2m9q4x1c8d3f6h0j5n",
  "key": "KR-7K2M9-Q4X1C-8D3F6-H0J5N",
  "fingerprint": "7a1acf765768ebbc09bfbbac0878d5e729d655a4be4db7510d2188f630881134",
  "platform": "windows",
  "appVersion": "1.4.2"
}

Response 200: { "certificate": "KR1…" }. Fails with 404 not_activated if this fingerprint has no activation on the license. Updates the activation’s lastSeenAt.

The SDKs call validate during their license check once the certificate’s refreshAfter has passed. They keep the cached certificate on network errors, 429 and 5xx, and clear it on 403 and on 404 unknown_key, unknown_product or not_activated.

Deactivate#

POST /v1/licenses/deactivate

json
{
  "product": "prd_7k2m9q4x1c8d3f6h0j5n",
  "key": "KR-7K2M9-Q4X1C-8D3F6-H0J5N",
  "fingerprint": "7a1acf765768ebbc09bfbbac0878d5e729d655a4be4db7510d2188f630881134"
}

Response 200: { "deactivated": true }. The seat is free for another machine. The app should delete its stored certificate (the SDKs do, and also when the answer is 404; on a network error they keep it so the call can be retried).

Errors#

Every error has the same shape:

json
{ "error": { "code": "activation_limit", "message": "This license is already active on 2 machines." } }

message is human-readable English, fine to log but not meant to be parsed. Branch on code. What to tell your customer for each code: troubleshooting.

HTTPcodeWhen
400invalid_requestMalformed body, bad fingerprint, bad key format.
404unknown_productNo product with this ID.
404unknown_keyNo license with this key for this product.
404not_activatedThis fingerprint has no activation on the license.
403license_expiredPast validUntil.
403license_suspendedSuspended by the vendor, or subscription paused.
403license_refundedRefunded.
403license_revokedRevoked (chargeback or manual).
403account_closedActivation only: the vendor closed its Keyrail account. Machines already activated keep validating for 30 days.
409activation_limitAll activations are in use.
429rate_limitedToo many calls.
500internal_errorOur fault. Retry later; the stored certificate keeps working.

Activation limit#

The limit is plan.maxActivations × license.seats, unless the vendor overrides maxActivations on the license.

Rate limits#

  • 30 calls per hour per license key and IP address.
  • 600 calls per hour per IP address.

The SDKs stay far below this: one call at activation, then at most about one refresh a day.

View as Markdown

Need help? See Troubleshooting or write to support@keyrail.tech.