licencebook

The method

Written 13 October 2026. The contract this page explains is licence-v1.md; the tests in the repository hold the code to it.

A key is made from the subscription

When a customer subscribes to a paid plugin, Stripe creates a subscription with an id such as sub_1Q…. licencebook turns that id into a key with an HMAC-SHA256 under a secret salt and keeps the first 40 hex characters, so the key reads lb_ and then 40 characters. The same subscription always gives the same key, and nobody holding the key can work back to the subscription. The salt is the one secret the key depends on, and it lives in the server's environment, nowhere else.

What Stripe holds, and why there is no licence database

On issuing a key, licencebook writes two values onto the subscription's metadata: the product the key is for, and the SHA-256 of the key. The key itself is printed once to the operator and stored nowhere. A check finds the subscription by that hash with Stripe's search, derives the key again from the subscription id and compares the two, so a hash copied onto another subscription opens nothing. Revoking a key writes a third value, the date it was revoked. If every store we run were lost tonight, every key would still check tomorrow from Stripe and the salt.

Stripe's search catches up with a new key within about a minute of issue. A plugin that checks in that first minute gets unknown_key and asks again on its next check.

Seats are the one thing Stripe cannot hold

A seat is one site a key is switched on for. Which sites hold a seat lives in one Redis set per subscription on a Vercel KV store. Without the store, a check still answers from Stripe and says sites_used: null, and an activation answers 503 naming the two variables it needs. Losing the store loses the seat counts and nothing else; customers activate their sites again.

The signed answer

Every granted answer carries a token: the answer itself, written as canonical JSON (keys sorted, no spaces, whole numbers only, the fleet's form from fleet-attestation) and signed with Ed25519. The plugin checks the signature with our public key, compiled into the plugin, and keeps the answer until cache_until, 24 hours after the check. If licencebook is down, slow or unreachable, the plugin keeps working on its last good answer. A paying customer is never switched off by our outage.

The plugin trusts a token only when the signature verifies, the domain reads licencebook:licence:v1, the site and product are its own, the key id matches its key, and the window is still open. The reference clients in the repository, one PHP class for WordPress and one TypeScript module for a Shopify app, do all six checks.

What a licence check cannot stop

A WordPress plugin is GPL code running on the customer's own server, so anyone willing to edit it can delete the check. No licence server changes that, and we will not pretend it does. What the key controls is what we control: updates, support, and the hosted features that run on our servers. The check is there so an honest customer's paid tier switches on without friction and switches off when the subscription ends.

Who it is for

Our own plugins first, served free: NoticeSolved's AI Act, Cookie Consent and Accessibility Pro add-ons, and AEOSearch for WordPress. Then any plugin maker who wants the same desk on their own Stripe account, on the hosted tier at $29 a month for up to 1,000 keys.