minmaxkey

How it works

How it works

MinMaxKey is a small server that issues license keys for the software you sell and checks them when customers run your app. One container, two minutes to deploy, works offline.

This page is the whole mental model. Everything else in these docs is reference for one of the steps here.

The loop, start to finish

1. YOU DEPLOY          docker run — one container, your machine
2. YOU CREATE          a product ("PixelForge Pro") — you get two things to
                       embed in your app: an api_key and a public key
3. CUSTOMER BUYS       Stripe → payment → MinMaxKey issues a license key
                       and emails it to the buyer
4. CUSTOMER ACTIVATES  they paste the key into your app → your app calls
                       MinMaxKey once → the key locks to their machine
5. YOUR APP VERIFIES   the activation returns a signed offline token; your app
                       checks it locally — works with no internet after that
6. YOU STAY IN CONTROL revoke on a refund, free a seat on reinstall, watch
                       devices in the dashboard

That's the product. Everything else is details.

Two directions, don't mix them up

MinMaxKey talks to two different kinds of software, and it's worth being explicit because "webhook" blurs it:

                    ┌──────────── your server (you) ────────────┐
                    │                                            │
   STRIPE ──payment──▶ MinMaxKey ──license.created/revoked──▶ YOUR SERVER
                    │                                            │
                    └────────────────────────────────────────────┘
                       (server-to-server, via webhooks)

                    ┌──────────── your customer's machine ──────┐
                    │                                            │
   YOUR APP ──activate/validate──▶ MinMaxKey  (the SDK, direct calls)
   YOUR APP ──verifies the signed token locally, offline────────▶ OK
                    └────────────────────────────────────────────┘
  • Webhooks are server-to-server. Payment providers post into MinMaxKey (Stripe's invoice.paid, refunds); MinMaxKey posts out to your backend (license.created, license.revoked) so you can react — cut off a refunded customer's cloud account, update your own records. Your webhook receiver is optional for a desktop app: if the license state lives entirely in MinMaxKey, you never need to receive a webhook.
  • The SDK is what your app uses. It's not a webhook. The customer's app calls MinMaxKey directly to activate/validate, and verifies the signed offline token locally so your app keeps working when it's offline. If you ship a VS Code extension, a desktop app, a Unity game — the SDK is the piece that goes inside it.

The four objects

Product ──▶ License type ──▶ License ──▶ Activation(s)
   │                          │
   └── public key (embed      └── the key string your customer
        in your app)               types: 9TMC-5TS9-0MKQ-VS8A-87Q0
  1. Product — one app you sell. Gives you an api_key (gates activate/validate; treat it as public) and a public_key (embed the PEM in your app for offline token verification).
  2. License type — how a license behaves: lifetime, subscription (expires after N days), trial, or floating (seat count is the whole story). Each has a seat limit: max_seats machines bound at once.
  3. License — one issued key. Status, optional customer email, optional metadata. The key has a checksum, so your app can reject typos without asking the server.
  4. Activation — binds a license to one machine fingerprint. Same machine reuses its seat; a new machine consumes one until max_seats; deactivation frees a seat; revocation stops every machine validating.

Offline tokens, in one sentence

Every activation returns an Ed25519-signed token your app verifies locally — so a revoked license keeps working until the app next checks in (minutes to days, your call), and the public key living in your binary is the cost of that. Read the honest trade-off.

Where to go next