A dead-simple software licensing API built for developers

For licensing desktop apps, on-premise software, and other digital products.

Get Started Free

Quit wasting time fighting with other licensing “solutions”

  • checkSell independently outside of the confines of the app stores, pocket that extra 30%, and handle licensing how you want.
  • checkSupport a wider range of platforms by using a licensing system that doesn't rely on a specific OS (aren't APIs great?!)
  • checkShip faster and stop wasting time (and money!) writing custom licensing servers that don't have all the features you want.

and last but not least…

  • closeNo gimmicky third-party installers that you have to package with your product (and that you have no control over!)
# Create a new license for a user of the “ecorp” account
curl https://api.keygen.sh/v1/accounts/ecorp/licenses -X POST \
  -H 'Authorization: Bearer a9f93c31b41642248db99fc04f4e8482.ebbe297ffbed4ccc837733e335bd8181…' \
  -H 'Content-Type: application/vnd.api+json' \
  -H 'Accept: application/vnd.api+json' \
  -d '{
        "data": {
          "type": "licenses",
          "attributes": {
            "key": "B8A5-91D7-CB9A-DAE4-4F6E-1128"
          },
          "relationships": {
            "policy": {
              "data: { "type": "policies", "id": "fbc29532…" }
            },
            "user": {
              "data: { "type": "users", "id": "592032dd…" }
            }
          }
        }
      }'
security

Control

Control what types of licenses your product offers using powerful license policies—from feature licenses to timed trials, we got you covered.

verified_user

Monitor

Quit guessing how many machines your users have—using our machine tracking endpoints you can know exactly where your product is being used.

Know what's working

…and what isn't. With Keygen's dashboard, you can always be on top of what's happening with your products.

  • trending_upView recent trends for new users, licenses, and much more
  • listWatch an up-to-date activity feed of what's happening
  • timelineGain insight into how users are licensing your products
  • star_halfKnow which types of licenses your users prefer

Use your favorite language

Quickly implement Keygen in the programming language of your choice.

const fetch = require("node-fetch")

// Replace this with a token that belongs to a user
const token = "9fc6d1e049a8414a905524dfa8c24a6b.d2b7366c85974bb09ef00b1b1ec22fd0.5a5dc7…"

// Set up request headers
const headers = {
  "Content-Type": "application/vnd.api+json",
  "Accept": "application/vnd.api+json",
  "Authorization": `Bearer ${token}`
}

// Request the current user's licenses for our product
const url = new URL("https://api.keygen.sh/v1/accounts/9fc6d1e0-49a8-414a-9055-24dfa8c24a6b/licenses")
url.searchParams.append("product", "14c80537-66c7-4753-a5e7-e8269a2ea616")

const licenses = await fetch(url, { headers })

const { data, errors } = await licenses.json()
if (!data) {
  process.exit() // User does not have any licenses
}

// Validate the first license we get back
const license = data[0]
const validation = await fetch(
  `https://api.keygen.sh/v1/accounts/9fc6d1e0-49a8-414a-9055-24dfa8c24a6b/licenses/${license.id}/actions/validate`,
  { headers }
)
const { meta } = await validation.json()

if (meta.valid) {
  // Do something
} else {
  // Do something else
}
import SwiftyJSON
import Alamofire

// Replace this with a token that belongs to a user
let token = "9fc6d1e049a8414a905524dfa8c24a6b.d2b7366c85974bb09ef00b1b1ec22fd0.5a5dc7…"

// Set up request headers
let headers: HTTPHeaders = [
  "Content-Type": "application/vnd.api+json",
  "Accept": "application/vnd.api+json",
  "Authorization": "Bearer \(token)"
]

// Request the current user's licenses for our product
let licensesUrl = "https://api.keygen.sh/v1/accounts/9fc6d1e0-49a8-414a-9055-24dfa8c24a6b/licenses"

Alamofire.request(licensesUrl, parameters: ["product": "14c80537-66c7-4753-a5e7-e8269a2ea616"], headers: headers)
  .responseJSON { response in
    let json = JSON(data: response.data!)

    guard let licenseId = json["data"][0]["id"].string else {
      abort() // User does not have any licenses
    }

    // Validate the first license we get back
    let licenseUrl = "https://api.keygen.sh/v1/accounts/9fc6d1e0-49a8-414a-9055-24dfa8c24a6b/licenses/\(licenseId)/actions/validate"

    Alamofire.request(licenseUrl, headers: headers)
      .responseJSON { response in
        let json = JSON(data: response.data!)
        let valid = json["meta"]["valid"].bool

        if valid {
          // Do something
        } else {
          // Do something else
        }
      }
  }
using EasyHttp.Http;
using System;

// Replace this with a token that belongs to a user
var token = "9fc6d1e049a8414a905524dfa8c24a6b.d2b7366c85974bb09ef00b1b1ec22fd0.5a5dc7…";

// Set up http client and request headers
var http = new HttpClient();
http.Request.ContentType = "application/vnd.api+json";
http.Request.Accept = "application/vnd.api+json";
http.Request.Authorization = $"Bearer {token}";

// Request the current user's licenses for our product
var licenses = http.Get(
  "https://api.keygen.sh/v1/accounts/9fc6d1e0-49a8-414a-9055-24dfa8c24a6b/licenses",
  new {product = "14c80537-66c7-4753-a5e7-e8269a2ea616"}
);
var body = licenses.DynamicBody;

if (body.Data == null || body.Data.length == 0)
{
  Environment.Exit(0); // User does not have any licenses
}

// Validate the first license we get back
var license = body.Data.First();
var validation = http.Get($"https://api.keygen.sh/v1/accounts/9fc6d1e0-49a8-414a-9055-24dfa8c24a6b/licenses/{license.Id}/actions/validate");
body = validation.DynamicBody;

if (body.Meta.Valid)
{
  // Do something
}
else
{
  // Do something else
}
import requests
import os

# Replace this with a token that belongs to a user
token = "9fc6d1e049a8414a905524dfa8c24a6b.d2b7366c85974bb09ef00b1b1ec22fd0.5a5dc7…"

# Set up request headers
headers = {
  "Content-Type": "application/vnd.api+json",
  "Accept": "application/vnd.api+json",
  "Authorization": "Bearer {0}".format(token)
}

# Request the current user's licenses for our product
licenses = requests.get(
  "https://api.keygen.sh/v1/accounts/9fc6d1e0-49a8-414a-9055-24dfa8c24a6b/licenses",
  params={ "product": "14c80537-66c7-4753-a5e7-e8269a2ea616" },
  headers=headers
).json()

if not licenses["data"]:
  quit() # User does not have any licenses

# Validate the first license we get back
license = licenses["data"][0]
validation = requests.get(
  "https://api.keygen.sh/v1/accounts/9fc6d1e0-49a8-414a-9055-24dfa8c24a6b/licenses/{1}/actions/validate".format(license["id"]),
  headers=headers
).json()

if validation["meta"]["valid"]:
  # Do something
else:
  # Do something else
require "httparty"

# Replace this with a token that belongs to a user
token = "9fc6d1e049a8414a905524dfa8c24a6b.d2b7366c85974bb09ef00b1b1ec22fd0.5a5dc7…"

# Set up request headers
headers = {
  "Content-Type" => "application/vnd.api+json",
  "Accept" => "application/vnd.api+json",
  "Authorization" => "Bearer #{token}"
}

# Request the current user's licenses for our product
licenses = HTTParty.get(
  "https://api.keygen.sh/v1/accounts/9fc6d1e0-49a8-414a-9055-24dfa8c24a6b/licenses",
  query: { product: "14c80537-66c7-4753-a5e7-e8269a2ea616" },
  headers: headers
)

if licenses["data"].empty?
  exit # User does not have any licenses
end

# Validate the first license we get back
license = licenses["data"].first
validation = HTTParty.get(
  "https://api.keygen.sh/v1/accounts/9fc6d1e0-49a8-414a-9055-24dfa8c24a6b/licenses/#{license['id']}/actions/validate",
  headers: headers
)

if validation["meta"]["valid"]
  # Do something
else
  # Do something else
end
require __DIR__ . "/vendor/autoload.php";

// Replace this with a token that belongs to a user
$token = "9fc6d1e049a8414a905524dfa8c24a6b.d2b7366c85974bb09ef00b1b1ec22fd0.5a5dc7…";

// Set up request headers
$headers = [
  "Content-Type" => "application/vnd.api+json",
  "Accept" => "application/vnd.api+json",
  "Authorization" => "Bearer {$token}"
];

// Request the current user's licenses for our product
$licenses = json_decode(
  Requests::request(
    "https://api.keygen.sh/v1/accounts/9fc6d1e0-49a8-414a-9055-24dfa8c24a6b/licenses",
    $headers, ["product" => "14c80537-66c7-4753-a5e7-e8269a2ea616"]
  )->body
);

if (!$licenses->data) {
  exit; // User does not have any licenses
}

// Validate the first license we get back
$license = $licenses->data[0];
$validation = json_decode(
  Requests::request(
    "https://api.keygen.sh/v1/accounts/9fc6d1e0-49a8-414a-9055-24dfa8c24a6b/licenses/{$license->id}/actions/validate",
    $headers
  )->body
);

if ($validation->meta->valid) {
  // Do something
} else {
  // Do something else
}

Learn how to…

  • codeeasily implement Keygen to handle licensing for your product
  • done_allquickly set up user registration and license validation
  • synchandle webhooks to integrate with your payment system

and of course…

  • playlist_add_checka full API reference with examples in popular languages
  • mail_outlineawesome email support

Not ready to join? Stay updated.

Integrate Keygen with software built on…

WordPress

WordPress plugin licensing example coming soon

Swift

Mac app licensing example coming soon
and more!

FAQs

  • What is Keygen?

    Keygen is a hosted SaaS (software-as-a-service) for licensing and managing users for desktop apps and other types of software. Keygen's primary product is an API that enables developers to quickly set up licensing and user management.

  • Who is Keygen for?

    Keygen is primarily built for small- and medium-sized businesses who build desktop applications, on-premise software, and other digital products e.g. WordPress plugins, etc. We also offer on-premise options for larger companies that are interested in using Keygen.

  • Why was Keygen created?

    From terrible “enterprisey” documentation to ridiculous pricing—we all know that the current state of product licensing sucks. Keygen aims to make licensing software for small businesses easy, letting you ship your product earlier and not waste time building a custom licensing server.

  • Can Keygen help lower support costs?

    Yes! One of the things that makes Keygen unique is that we encourage you to allow your users to manage their own resources i.e. their licenses and machines, while you respond to the appropriate webhook events to handle billing using your payment provider. This not only gives your users freedom to purchase additional licenses directly from within your product without your help (offering a great user-experience and potential for more sales!) but can also lower your licensing-related support costs.

  • What licensing models are supported?

    Keygen supports almost any licensing model: generating and validating license keys, single machine-locked licenses, floating licenses with and without machine limits, feature-based licenses, limited pre-determined pool-based licenses, encrypted and unencrypted licenses, licenses that require periodic check-in, and even a combination of most of those.

  • Does Keygen prevent sharing licenses?

    Yes! Keygen offers API endpoints to help you track user machine usage, and license policies can be configured to strict, invalidating licenses that go over any configured machine limit. You can also set license policies to floating to allow licenses to be valid across multiple machines.

  • Does Keygen prevent cracking?

    No. Keygen does nothing to prevent a user from removing your licensing logic altogether if they have access to your application's code. In the end, you will have to make the choice on how to deal with cracking by e.g. requiring a valid license for updates, requiring a licensed user-account for support requests, etc.

  • Where can I monitor Keygen's uptime?

    We strive to provide the highest uptime possible. You can monitor our uptime and average response time on our status page.

  • Is data within Keygen secure?

    Yes. We strive to ensure that the data stored within Keygen is as secure as possible. We never store passwords as plain text – they are always hashed and salted securely using bcrypt. We also do the same with all access tokens, and offer the ability to hash license keys as well. All network traffic is encrypted over TLS with at least 128-bit AES encryption. Have additional questions or concerns? Get in touch.

  • Does Keygen work offline?

    Yes, but it requires manual work. Using Keygen's admin dashboard, you can manually create, check-in and verify licenses, allowing you to offer phone activation or a similar service. For automatic license validation and to track machine usage, Keygen will require an active (or periodic) internet connection.

  • Does Keygen handle payments?

    No—only licensing. Since products handle payments in a variety of ways (and we don't want to become a payment platform), we have created a webhook system so that you can easily integrate your payment system with our API. Implementation is similar to how you would implement Stripe's webhook system. Learn more about webhooks.

  • Do you offer on-premise API plans?

    Yes. We're very interested in talking with companies that would rather host our software licensing server in-house. Get in touch.

  • Do you offer open source plans?

    Most definitely. If you want to use Keygen for an open source project, send us a link to your project and we will review it to determine if it's eligible for a free open source plan.

  • Can I use Keygen for an iOS app?

    Yes and no. Unfortunately, it isn't possible at this time to use Keygen for paid app-related licenses. Apple’s developer terms require that purchases related to an app, such as premium content and add-ons are managed via their native In-App Purchase API.

  • Can I use Keygen for an Android app?

    Yes and no. Unfortunately, it isn't possible at this time to use Keygen for paid app-related licenses. Google's developer policy requires that purchases related to an app, such as premium features and add-ons are managed via their native In-App Billing API.