DEV Community

Keyturn Kit
Keyturn Kit

Posted on Originally published at keyturnkit.github.io

Payhip license keys in a Chrome extension, with a secret that's allowed to ship

Most license APIs give you one account key that must never leave a server, which is awkward when your product is a Chrome extension with no server at all. Payhip's v2 license API is different. Each product has its own secret key, and Payhip's help center says that one is meant for public apps. We just added Payhip to Keyturn Kit, our starter for selling extensions, so here is how the endpoints behave and where the limits are. The details come from Payhip's help article on software license keys, read on 27 October 2026.

Turn license keys on

In Payhip, turn on license keys for the product. Its license settings show the product secret key, and that's the value the extension sends. Your account API key stays out of it.

Add https://payhip.com/* to host_permissions in your manifest.

Checking a key

GET https://payhip.com/api/v2/license/verify?license_key=..., with the secret in a product-secret-key header:

const res = await fetch(
  `https://payhip.com/api/v2/license/verify?license_key=${encodeURIComponent(key)}`,
  { headers: { 'product-secret-key': PRODUCT_SECRET } },
);
const text = await res.text();
const license = text ? JSON.parse(text).data : null; // empty response = no such key
Enter fullscreen mode Exit fullscreen mode

A good key comes back as data with enabled, license_key, buyer_email, uses and date. An unknown key gives an empty response rather than an error, so the check has to treat "nothing came back" as "not a key" instead of trying to parse it.

Counting browsers with uses

There are no activations as such, but every key has a uses number you can move up and down with the same secret.

  • PUT /api/v2/license/usage adds one. Call it once when the key is pasted, after checking that uses is below the number of browsers you allow.
  • PUT /api/v2/license/decrease takes one off. Call it when someone removes the key, so moving to a new laptop frees a slot.
  • The daily re-check only calls verify, which leaves the count alone.

Refunds

Payhip disables the key by itself when an order is refunded. The next verify returns enabled: false and the extension can lock the paid features. Nothing to do in the dashboard.

How far the secret reaches

The secret ships inside the extension, and anyone can unzip an extension. With it, someone who already holds a key can call decrease on that key and reset their own count, so the browser limit is soft. They can't create keys or unlock keys they don't have. That's the trade Payhip made by letting public apps call these endpoints. If a hard limit matters to you, the check belongs on a server.

In Keyturn Kit

Keyturn Kit is a WXT + React starter that does the above. The free edition (MIT, on GitHub) uses Lemon Squeezy. Payhip, Gumroad, Polar and Dodo Payments come with Pro ($59 once), where switching provider is one line in lib/config.ts:

provider: 'payhip',
payhip: { productSecretKey: 'YOUR-PAYHIP-PRODUCT-SECRET-KEY', maxUses: 3 },
Enter fullscreen mode Exit fullscreen mode

The full guide, with the same code, is on our site.

Top comments (0)