License Docs

API Reference

The raw HTTP contract. Use this if you're integrating from a language without a ready-made SDK, or want to see exactly what the SDKs do under the hood.

Base URL: loading…

Conventions

GET /api/v1/public-key

No auth, no rate limit beyond the general limiter. Returns the Ed25519 public key used to sign every activate/verify response.

{ "publicKey": "base64-spki-der...", "algorithm": "ed25519" }

POST /api/v1/activate

Binds a key to a device on first use. Idempotent if called again with the same hwid. Rate limited: 10 requests / 10 min per IP, and 20 / hour per key.

Request

{
  "product": "your-product-slug",
  "key": "7K2M9-QX3R8-2VBN5-8JH4C-T",
  "hwid": "sha256-hex-of-a-machine-id"    // see Security Model page
}

POST /api/v1/verify

Checks whether a previously-activated key is still valid on this device. Does not activate — a key that has never been activated returns reason: "not_activated" (SDKs handle this by calling /activate automatically). Rate limited: 30 requests / min per IP, and 120 / hour per key.

Request

{
  "product": "your-product-slug",
  "key": "7K2M9-QX3R8-2VBN5-8JH4C-T",
  "hwid": "sha256-hex-of-a-machine-id"
}

Response (both endpoints)

A signed envelope. See the Security Model page for exactly how to verify signature against payload.

{
  "payload": {
    "valid": true,
    "reason": null,
    "product_slug": "your-product-slug",
    "key_id": 42,
    "hwid_bound": true,
    "status": "active",
    "expires_at": "2027-01-01T00:00:00.000Z",
    "issued_at": "2026-09-04T12:00:00.000Z",
    "offline_grace_until": "2026-09-07T12:00:00.000Z"
  },
  "signature": "base64..."
}

reason values

ValueMeaning
nullSuccess — valid is true.
not_foundNo such key for that product (or the key belongs to a different product).
malformed_keyThe key string fails its checksum — almost always a typo. Never hits the database.
revokedAn admin revoked this key.
expiredPast its computed or fixed expiry date.
hwid_mismatchThis key is already bound to a different device.
not_activated/verify only — this key has never been activated on any device yet.

Admin API

Powers the dashboard at /admin/. You can also script it — e.g. to auto-generate a key from your own checkout/fulfillment webhook. It's cookie-session authenticated, so from a script: log in once, keep the cookie, reuse it.

# log in and save the session cookie
curl -c cookies.txt -X POST .../api/admin/auth/login \
  -H 'content-type: application/json' \
  -d '{"username":"admin","password":"..."}'

# generate 1 key for product id 1, expiring 30 days after activation
curl -b cookies.txt -X POST .../api/admin/keys \
  -H 'content-type: application/json' \
  -d '{"productId":1,"count":1,"durationDays":30,"customerEmail":"buyer@example.com"}'

Full admin routes: /api/admin/auth/*, /api/admin/products, /api/admin/keys, /api/admin/stats — the request/response shapes mirror what the dashboard sends; open your browser's network tab on /admin/ for exact examples.