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.
fingerprintis the 64-character lowercase hex machine fingerprint.
Activate#
POST /v1/licenses/activate
{
"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:
{ "certificate": "KR1.eyJ2IjoxLCJraWQiOiJrMSIs….1qOAhxQWB0OO…", "activation": "act_9c4h7k1m5p8r2t6v0x3z" }Idempotent: activating a fingerprint that is already activated refreshes it and does not use another seat.
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:
{
"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
{
"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:
{ "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.
| HTTP | code | When |
|---|---|---|
| 400 | invalid_request | Malformed body, bad fingerprint, bad key format. |
| 404 | unknown_product | No product with this ID. |
| 404 | unknown_key | No license with this key for this product. |
| 404 | not_activated | This fingerprint has no activation on the license. |
| 403 | license_expired | Past validUntil. |
| 403 | license_suspended | Suspended by the vendor, or subscription paused. |
| 403 | license_refunded | Refunded. |
| 403 | license_revoked | Revoked (chargeback or manual). |
| 403 | account_closed | Activation only: the vendor closed its Keyrail account. Machines already activated keep validating for 30 days. |
| 409 | activation_limit | All activations are in use. |
| 429 | rate_limited | Too many calls. |
| 500 | internal_error | Our 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.
Need help? See Troubleshooting or write to support@keyrail.tech.