API Reference
JARVIS Kit ships with a license validation API at https://jarviskit.ai/api/validate. The kit's setup.sh calls it on first install. You can also call it directly to verify keys programmatically.
Base URL
https://jarviskit.ai/apiAuthentication
The validate endpoint is public, the license key itself acts as the secret. There is no separate API token. CORS is enabled (Access-Control-Allow-Origin: *).
POST /api/validate
Validates a license key. Returns whether the key is currently active, the tier it grants, and (optionally) an expiration timestamp.
Request
POST /api/validate HTTP/1.1
Host: jarviskit.ai
Content-Type: application/json
{
"key": "JK-1234-5678-ABCD",
"machineId": "a1b2c3d4e5f6...",
"version": "1.0.0"
}Body fields
| Field | Type | Required | Description |
|---|---|---|---|
key | string | yes | The buyer's license key. Format depends on your backend (LemonSqueezy, Polar, Gumroad, KV, or static). |
machineId | string | recommended | SHA-256 hash slice of hostname-username-platform-arch. Used by some backends (LemonSqueezy) to bind a key to a machine. |
version | string | optional | Kit version the buyer is installing. Logged for analytics, not validated. |
Response (200 OK, valid key)
{
"valid": true,
"tier": "starter",
"expiresAt": "2026-12-31T23:59:59Z"
}Response (200 OK, rejected)
{
"valid": false,
"message": "License rejected by LemonSqueezy"
}Note: rejected keys still return HTTP 200 with valid: false. The kit's validate.js handles this. We use 200 (not 401/403) so middleware doesn't accidentally retry or strip the body.
Response fields
| Field | Type | When present |
|---|---|---|
valid | boolean | always |
tier | string | when valid (e.g. starter, pro, enterprise) |
expiresAt | ISO 8601 string | when valid + provider supports expiration |
message | string | when invalid (human-readable reason) |
GET /api/health
Liveness probe. Returns {"ok": true} with HTTP 200. No auth.
curl https://jarviskit.ai/api/health
{"ok": true}Examples
curl
curl -X POST https://jarviskit.ai/api/validate \
-H "Content-Type: application/json" \
-d '{
"key": "JK-1234-5678-ABCD",
"machineId": "a1b2c3d4e5f6",
"version": "1.0.0"
}'JavaScript (Node.js / browser)
const res = await fetch("https://jarviskit.ai/api/validate", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
key: process.env.JARVIS_KIT_KEY,
machineId: hashId(),
version: pkg.version,
}),
});
const data = await res.json();
if (!data.valid) throw new Error(data.message);
console.log("activated tier:", data.tier);Python
import requests, hashlib, os, platform
machine_id = hashlib.sha256(
f"{os.uname().nodename}-{os.getlogin()}-{platform.system()}-{platform.machine()}".encode()
).hexdigest()[:16]
r = requests.post("https://jarviskit.ai/api/validate", json={
"key": "JK-1234-5678-ABCD",
"machineId": machine_id,
"version": "1.0.0",
})
data = r.json()
if not data["valid"]:
raise SystemExit(data["message"])
print("activated tier:", data["tier"])Backends
The validate endpoint can route to one of five backends, configured in the worker/wrangler.toml via the LICENSE_BACKEND env var:
| Backend | What it does | Config |
|---|---|---|
static | Match against comma-separated STATIC_KEYS env var | wrangler secret put STATIC_KEYS |
lemonsqueezy | Proxy to api.lemonsqueezy.com/v1/licenses/validate | No extra config |
polar | Proxy to api.polar.sh/v1/customer-portal/license-keys/validate | POLAR_ORG_ID required |
gumroad | Proxy to api.gumroad.com/v2/licenses/verify | GUMROAD_PRODUCT required |
kv | Cloudflare KV lookup (manual key insertion) | Bind VALID_KEYS_KV namespace |
Grace mode
The kit's validate.js implements grace mode: if the validate endpoint returns 5xx or is unreachable, the install proceeds with a 7-day provisional license. Re-validation runs in the background on subsequent launches.
This means: your buyer's install never fails because of provider downtime. They get full access for up to 7 days while you fix the upstream issue.
Rate limits
Cloudflare Workers free tier: 100,000 requests / day. The kit calls validate once per fresh install, well under any realistic limit. For very-high-volume products, upgrade to Workers Paid ($5/mo for 10M requests).
CORS
All responses include Access-Control-Allow-Origin: * and full method/header allowlists. The endpoint accepts OPTIONS preflight requests automatically.
Errors
| Status | When |
|---|---|
| 200 | Normal, check valid in body |
| 400 | Missing or malformed JSON body |
| 404 | Wrong path (only /api/validate + /api/health exist) |
| 405 | Wrong method (validate is POST-only) |
| 500 | Backend config issue (e.g. POLAR_ORG_ID unset for polar backend) |