minmaxkey

API reference

API reference

Base URL: http://your-server:8080. All responses are JSON. Interactive Swagger UI lives at /docs on your server.

Authentication

Two credentials, two header names:

Header Used for Set where
X-MinMax-Admin-Token management endpoints (CRUD, reset, revoke) your server only
X-API-Key activation / validation endpoints your client app

Wrong or missing credentials return 401.

Errors

Errors are JSON: {"detail": "..."} with a status code.

Code Meaning
401 bad or missing auth
404 unknown product / license / policy (or key doesn't exist)
403 license revoked, or expired
429 no seats available on this license
409 duplicate name / slug
422 validation error

/activate deliberately answers 404 for unknown keys — no key sniffing.

Endpoints

GET /healthz

Liveness probe. {"status": "ok", "service": "minmaxkey"}.

GET /

Service info: links to /docs, /admin, /healthz.

Products

POST /v1/products · admin Create a product. Body: {"name": "PixelForge Pro", "slug": "pixelforge-pro"}. Returns the product including api_key and public_key.

GET /v1/products · admin List all products.

GET /v1/products/{id} · admin One product.

POST /v1/products/{id}/webhook · admin Set (or clear, with {"url": ""}) the product's webhook endpoint. Returns {"url": ..., "secret": ...} — the secret is generated once and stays stable. Keep it server-side.

Policies

POST /v1/products/{id}/policies · admin Body: {"name": "pro-monthly", "kind": "subscription", "max_seats": 1, "duration_days": 30}. kind is one of lifetime | subscription | floating | trial. max_seats defaults to 0 (unlimited). duration_days applies to subscription/trial.

GET /v1/products/{id}/policies · admin

Licenses

POST /v1/products/{id}/licenses · admin Body: {"policy_id": 1, "customer_email": "[email protected]", "metadata": {...}}. policy_id must belong to that product. Returns the license including the human-friendly key.

GET /v1/products/{id}/licenses · admin All licenses of a product, each with its current activations.

POST /v1/licenses/{id}/revoke · admin Revokes the license. All future activations and validations fail; existing offline tokens keep working until the client revalidates (see Offline tokens for the trade-off).

POST /v1/licenses/{id}/reset · admin Frees every seat of the license in one go — the customer reinstalled their OS and their fingerprint changed. The key stays active and can bind a new machine immediately. Returns {"status": "reset", "freed": N} and fires license.reset.

POST /v1/licenses/{id}/offline · admin Returns {"token": "..."} — a signed offline token for a license not bound to a specific device.

Activation (client-facing, X-API-Key)

POST /v1/products/{id}/activate Body: {"key": "...", "fingerprint": "<sha256 hex, ≥8 chars>", "name": "My MacBook", "platform": "windows"}. Returns license, device, seat usage, and offline_token.

POST /v1/products/{id}/deactivate Body: {"key": "...", "fingerprint": "..."}. Idempotent: {"freed": true} or {"freed": false}.

GET /v1/products/{id}/validate?key=...&fingerprint=... Server-side status check for webhooks and payment processors. When a fingerprint is given and the license is valid, also returns a fresh offline_token — this is how clients auto-revalidate.

Response shape:

{
  "valid": true,
  "status": "active",
  "license": {"id": 1, "key": "9TMC-...", "status": "active", "expires_at": null, "...": "..."},
  "device": {"fingerprint": "9f86d081...", "platform": "windows", "...": "..."},
  "seats": {"used": 1, "max": 2},
  "offline_token": "eyJ..."
}

When invalid: {"valid": false, "status": "invalid" | "revoked" | "expired"}.