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/api

Authentication

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

FieldTypeRequiredDescription
keystringyesThe buyer's license key. Format depends on your backend (LemonSqueezy, Polar, Gumroad, KV, or static).
machineIdstringrecommendedSHA-256 hash slice of hostname-username-platform-arch. Used by some backends (LemonSqueezy) to bind a key to a machine.
versionstringoptionalKit 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

FieldTypeWhen present
validbooleanalways
tierstringwhen valid (e.g. starter, pro, enterprise)
expiresAtISO 8601 stringwhen valid + provider supports expiration
messagestringwhen 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:

BackendWhat it doesConfig
staticMatch against comma-separated STATIC_KEYS env varwrangler secret put STATIC_KEYS
lemonsqueezyProxy to api.lemonsqueezy.com/v1/licenses/validateNo extra config
polarProxy to api.polar.sh/v1/customer-portal/license-keys/validatePOLAR_ORG_ID required
gumroadProxy to api.gumroad.com/v2/licenses/verifyGUMROAD_PRODUCT required
kvCloudflare 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

StatusWhen
200Normal, check valid in body
400Missing or malformed JSON body
404Wrong path (only /api/validate + /api/health exist)
405Wrong method (validate is POST-only)
500Backend config issue (e.g. POLAR_ORG_ID unset for polar backend)