Sell your app with Stripe. Let the license keys take care of themselves.

A customer pays; a license key lands in their inbox; your app checks it offline with a public key you embed; a refund turns it off. License Keeper is the open-source server that does the middle of that, in your own account, with no per-license fee. Try the key format below. Everything runs in your browser, so nothing here is uploaded.

1. Make a key pair and sign a test license

2. Verify a license, offline

Result: not checked

ClaimValue

Change one character of the key and verify again: the signature fails. That is all an app needs to run offline.

3. Run the server yourself

git clone https://github.com/Duncan-Haywood/fp-monorepo && cd fp-monorepo/ventures/license-keeper
STRIPE_SECRET_KEY=rk_live_... STRIPE_WEBHOOK_SECRET=whsec_... ADMIN_KEY=$(openssl rand -hex 16) \
PLANS_JSON='{"price_123":{"product":"myapp","plan":"pro","machines":2,"days":null}}' \
RESEND_API_KEY=re_... MAIL_FROM="Acme <keys@example.com>" COMPANY_NAME=Acme \
node server.mjs          # DRY_RUN=true until you set DRY_RUN=false

Point a Stripe webhook at /webhook/stripe for checkout.session.completed, checkout.session.async_payment_succeeded, invoice.paid, customer.subscription.deleted, charge.refunded and charge.dispute.created. Your app posts /v1/activate with the license and a machine fingerprint. One-click Render deploy and Docker are in the README.

Questions

Why not just use Keygen, Lemon Squeezy or Gumroad license keys?

Hosted licensing services are good and quick to start, and Lemon Squeezy and Gumroad hand you a key as part of checkout. The catch is that the license data, the activation endpoint and the fees live on someone else's platform, and a random key can only be checked by calling that platform. License Keeper runs in your own account, signs keys with your own Ed25519 key so the app can verify them offline, and charges no per-license fee. If a hosted service already does the job for you, keep it.

Does the app need to call the server on every launch?

No. A license token is signed, so the app verifies it with the public key you embed and no network at all. It only calls the server to activate a machine, to refresh a token that is about to expire (subscriptions), and to learn about a revocation. Between those calls your customers can work offline.

What happens if I lose the signing key or the server goes down?

Tokens already issued keep verifying offline for as long as they are valid, because verification needs only the public key. Back up the state file: it holds the signing key unless you supply your own with SIGNING_PRIVATE_KEY, and without that key you cannot issue or refresh licenses that your embedded public key accepts.

How are refunds and chargebacks handled?

A full refund or a dispute on the original payment revokes the license. Apps that validate online see the revocation on their next check; a token already cached offline works until it expires, so use short-lived tokens for subscriptions and treat perpetual offline tokens as honour-system after a refund.

Is it safe to try?

It starts in dry-run mode: it issues and logs licenses but sends no email until you set DRY_RUN=false. Try it with a Stripe test-mode key first. It never writes to Stripe.