Sell software with license keys
Updated on 11 Aug 2026 · 7 min read
1. What license keys are
If you sell a plugin, app, script, or game, SupportKori can give every buyer a unique license key automatically. Your software then checks that key with us to confirm the person actually paid — and unlocks the paid features only if they did.
The key itself is just a random code. It’s “real” only because we recorded it when the sale happened. Your software proves a key by asking our verify endpoint — we’re the source of truth, so a made-up key never passes.
This is a deterrent, not unbreakable DRM — the same as Gumroad or any license system. It stops casual sharing and gives real buyers instant keys; a determined pirate editing your code can’t be fully stopped by anyone.
2. Turn it on & get your token
- 1
Create or edit a digital → instant product in your Dashboard → Shop.
- 2
Turn on “This is software” and set how many activations each key allows.
- 3
Save, then open the product’s License & connection page. Copy your product token — a public id you paste into your software (like a Gumroad product id).
Your product won’t go on sale until it’s connected — you have to prove your software talks to us first (step 4). This guarantees every licensed product on SupportKori actually works before anyone buys.
3. Add the check to your software
No matter what you’re building, it’s always the same three moves. Add these to your software and you’re done:
- 1
Let the buyer paste their key
Add a text field somewhere in your software's settings where the user types their license key, and save it (in your plugin options, a config file, local storage — wherever you already keep settings).
- 2
Check the key with us
When they click Activate (and again each time your software starts), send the saved key to our endpoint. Paste the check function below and call it with the key.
- 3
Unlock only if valid
If the reply's valid is true, run your paid features. If it's false, keep them locked and show a message.
Complete example: a WordPress plugin
Here’s a whole working mini-plugin. Create a file like wp-content/plugins/my-license/my-license.php and paste this in. The comments show exactly where each of the three moves lives:
<?php
/* Plugin Name: My Licensed Plugin */
// ── The check (paste this once, anywhere in the file) ────────────
function skori_check($key) {
$r = wp_remote_post('https://supportkori.com/api/licenses/verify', [
'body' => ['product_id' => '<YOUR-PRODUCT-TOKEN>', 'license_key' => $key],
]);
$d = json_decode(wp_remote_retrieve_body($r), true);
return !empty($d['valid']); // true = genuine
}
// ── MOVE 1: a settings field so the buyer can save their key ─────
add_action('admin_menu', function () {
add_options_page('License', 'License', 'manage_options', 'my-license', function () {
if (isset($_POST['skori_key'])) {
update_option('skori_key', sanitize_text_field($_POST['skori_key']));
echo '<div class="notice notice-success"><p>Saved.</p></div>';
}
$key = get_option('skori_key', '');
echo '<div class="wrap"><h1>License</h1><form method="post">
<input name="skori_key" value="' . esc_attr($key) . '" style="width:320px" />
<button class="button button-primary">Save & activate</button></form></div>';
});
});
// ── MOVE 2 + 3: check the saved key, then gate your feature ──────
function my_plugin_feature() {
$key = get_option('skori_key', '');
if (!$key || !skori_check($key)) {
return 'Please enter a valid license key on the License settings page.';
}
// ✅ Valid — put your real paid feature here.
return 'Premium feature is running!';
}Replace <YOUR-PRODUCT-TOKEN> with the token from your product’s License page. Everywhere you’d normally run a paid feature, wrap it in if (skori_check($key)) { … }.
Any other app (desktop, script, browser)
Same three moves. Paste one of these check functions wherever you keep your logic, then call it with the key the user saved — and only run your paid code when it returns true.
JavaScript / Node:
async function checkLicense(key) {
const r = await fetch('https://supportkori.com/api/licenses/verify', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ product_id: '<YOUR-PRODUCT-TOKEN>', license_key: key }),
});
return (await r.json()).valid; // true = genuine
}
// Use it:
if (await checkLicense(savedKey)) {
runPaidFeature(); // ✅ valid
} else {
showLockedMessage(); // ❌ invalid / refunded
}Python:
import requests
def check_license(key):
r = requests.post('https://supportkori.com/api/licenses/verify',
json={'product_id': '<YOUR-PRODUCT-TOKEN>', 'license_key': key})
return r.json().get('valid', False)
# Use it:
if check_license(saved_key):
run_paid_feature() # ✅ valid
else:
show_locked_message() # ❌ invalid / refundedWhen a key is rejected, the reply tells you why so you can show the right message:
| reason | Means |
|---|---|
| not_found | The key doesn't exist (fake or mistyped) |
| product_mismatch | The key belongs to a different product |
| seat_limit_reached | All of this key's activations are used |
| refunded | The order was refunded — access revoked |
| disabled | You disabled this key from your dashboard |
4. Test the connection
Your License & connection page has a free test key (it’s not a real sale). Run your software with it once — or paste the ready-made cURL command from that page into a terminal. The moment we receive the call, the page flips to Connected and your product goes on sale.
curl -X POST https://supportkori.com/api/licenses/verify \
-H "Content-Type: application/json" \
-d '{"product_id":"<YOUR-PRODUCT-TOKEN>","license_key":"<YOUR-TEST-KEY>"}'The page updates on its own — no need to refresh. If it’s still “Not connected”, double-check you copied the token exactly and that your code actually reached the endpoint.
5. Limit activations (seats)
Each key allows a number of installs (you set it in the product editor). To actually enforce that, send two extra fields when a buyer activates: increment_uses_count: true and a stable instance_id — a unique id for that machine that stays the same across restarts (e.g. a hashed device id).
{
"product_id": "<YOUR-PRODUCT-TOKEN>",
"license_key": "<the buyer's key>",
"increment_uses_count": true,
"instance_id": "this-machine-1234"
}Re-activating the same instance_id is free (it won’t use another seat). When all seats are taken, a new machine gets reason: "seat_limit_reached". For your startup re-check, leave increment_uses_count out — a plain check never consumes a seat.
6. Let buyers switch devices
Add a “Deactivate this device” button that frees a seat, so a buyer can move their license to a new computer:
POST https://supportkori.com/api/licenses/deactivate
{
"product_id": "<YOUR-PRODUCT-TOKEN>",
"license_key": "<the buyer's key>",
"instance_id": "this-machine-1234"
}That seat is immediately available again for the next install.
7. Refunds & revoking keys
Refunds revoke automatically
If a sale is refunded/removed by an admin, that buyer’s key stops verifying on its own — it starts returning reason: "refunded".
Disable a key yourself
On the License page’s Issued keys list, disable any key (e.g. abuse) — it fails verification instantly. Re-enable it anytime.
Regenerate a leaked key
Regenerate to issue the buyer a fresh key and kill the old one. The buyer switches to the new key; the leaked one is dead.
8. Set it up with AI (vibe coding)
Building your software with Cursor, Claude, ChatGPT, or Windsurf? You don’t have to write any of this by hand. Copy the prompt below, replace <YOUR-PRODUCT-TOKEN> with the token from your product’s License page, and paste it into your AI — it’ll wire the whole thing into your codebase for you.
Add SupportKori license-key checking to my software.
How SupportKori verification works:
- Endpoint: POST https://supportkori.com/api/licenses/verify
- Send JSON: { "product_id": "<YOUR-PRODUCT-TOKEN>", "license_key": "<the key the buyer entered>" }
- Reply: { "valid": true } for a genuine key, or { "valid": false, "reason": "..." } for a fake, refunded, or disabled key.
- My product token is: <YOUR-PRODUCT-TOKEN>
Build this into my software:
1. Add a settings field where the user enters and saves their license key.
2. When they activate, call the endpoint with product_id + license_key, PLUS "increment_uses_count": true and a stable "instance_id" (a unique id for this install that stays the same across restarts). If the reply reason is "seat_limit_reached", tell them they've used all their activations.
3. On every startup, call the endpoint again WITHOUT increment (just product_id + license_key) to re-check; if valid is false, lock the paid features.
4. Only unlock paid features when valid is true. Show a clear message when it's false.
5. Cache the last successful result for a few hours so the app still works briefly offline, but re-check when back online.
6. (Optional) To let a user move to a new machine, call POST https://supportkori.com/api/licenses/deactivate with { product_id, license_key, instance_id } to free a seat.
Tell me exactly where to paste each piece in my codebase, and keep it simple.After the AI adds it, run your software once with the test key from your License page to flip the connection to Connected. That’s it — you’re live.
9. Good to know
The token isn’t secret
It’s meant to live inside your distributed software, exactly like a Gumroad product id. The buyer’s key is the private part.
Keys arrive everywhere automatically
Each buyer gets their key on the success screen, in their delivery email, and in their SupportKori library — you don’t deliver anything by hand.
Check on launch, not every second
Verify on activation and on startup, then cache the result for a few hours. No need to call us on every action.
Works from anywhere
The endpoint is open and CORS-enabled, so it works from a server, a desktop app, or browser JavaScript alike.
Did this article help?