A dead-simple product licensing API built for developers

Request Beta Access

Easily manage licenses for your products

  • checkCreate and manage individual apps/products
  • checkCreate unique license policies per-product
  • checkCreate, validate and revoke license keys
  • checkCreate and manage user accounts
# 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.9a3b6c8eec01db86015e2236ddc71f60edfa65ad4358b583bde95d4d68275624ec271ec06992d25739e425e862bad41729acdbfda5098c4544db1451277009a3"' \
  -H 'Content-Type: application/vnd.api+json' \
  -H 'Accept: application/vnd.api+json' \
  -d '{
        "data": {
          "type": "licenses",
          "relationships": {
            "policy": {
              "data: { "type": "policies", "id": "fbc29532-f2ec-4e34-8af0-99debed700cb" }
            },
            "user": {
              "data: { "type": "users", "id": "592032dd-25f3-4d1d-ad72-3f5eba2503c0" }
            }
          }
        }
      }'

Powerful business metrics

  • trending_upMonitor crucial events for users, licenses and more
  • notifications_noneGet notified of overdue check-ins and expirations
  • timelineGet insights into user behavior and preferences
  • dvrTrack user machine usage and allowed limits

Use your favorite language

Quickly implement Keygen in the programming language of your choice.

const fetch = require("node-fetch")

const REQUEST_BASEURL = `https://api.keygen.sh/v1/accounts/${process.env.KEYGEN_ACCOUNT_ID}`
const REQUEST_HEADERS = {
  "Content-Type": "application/vnd.api+json",
  "Accept": "application/vnd.api+json"
}

async function main() {
  var data, errors

  // … prompt user for email and password

  const credentials = new Buffer(`${email}:${password}`).toString("base64")

  // Authenticate the user by creating a new token
  const auth = await fetch(`${REQUEST_BASEURL}/tokens`, {
    headers: { ...REQUEST_HEADERS, "Authorization": `Basic ${credentials}` },
    method: "POST"
  })

  // Get the newly created authentication token
  var { data, errors } = await auth.json()
  if (errors) {
    // … handle invalid credentials
    process.exit()
  }

  const { attributes: { token } } = data

  // Check if they have a license for a specific product feature
  const licenses = await fetch(`${REQUEST_BASEURL}/licenses?product=${process.env.KEYGEN_PRODUCT_ID}&policy=${process.env.KEYGEN_FEATURE_POLICY_ID}`, {
    headers: { ...REQUEST_HEADERS, "Authorization": `Bearer ${token}` },
    method: "GET"
  })

  // Validate the first license we get back
  var { data } = await licenses.json()
  if (!data) {
    process.exit() // User does not have a license for the feature
  }

  const validation = await fetch(`${REQUEST_BASEURL}/licenses/${data[0]['id']}/actions/validate`, {
    headers: { ...REQUEST_HEADERS, "Authorization": `Bearer ${token}` },
    method: "GET"
  })

  const { meta } = await validation.json()

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

main()
import requests
import os

REQUEST_BASEURL = "https://api.keygen.sh/v1/accounts/{0}".format(os.environ["KEYGEN_ACCOUNT_ID"])
REQUEST_HEADERS = {
  "Content-Type": "application/vnd.api+json",
  "Accept": "application/vnd.api+json"
}

# … prompt user for email and password

# Authenticate the user by creating a new token
auth = requests.post("{0}/tokens".format(REQUEST_BASEURL),
  headers=REQUEST_HEADERS,
  auth=(email, password)
).json()

# Get the newly created authentication token
if auth["errors"]:
  # … handle invalid credentials
  quit()

token = auth["data"]["attributes"]["token"]

# Check if they have a license for a specific product feature
licenses = requests.get("{0}/licenses?product={1}&policy={2}".format(REQUEST_BASEURL, os.environ["KEYGEN_PRODUCT_ID"], os.environ["KEYGEN_FEATURE_POLICY_ID"]),
  headers={ **REQUEST_HEADERS, "Authorization": "Bearer {0}".format(token) }
).json()

# Validate the first license we get back
if not licenses["data"]:
  quit() # User does not have a license for the feature

validation = requests.get("{0}/licenses/{1}/actions/validate".format(REQUEST_BASEURL, licenses["data"][0]["id"]),
  headers={ **REQUEST_HEADERS, "Authorization": "Bearer {0}".format(token) }
).json()

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

REQUEST_BASEURL = "https://api.keygen.sh/v1/accounts/#{ENV['KEYGEN_ACCOUNT_ID']}"
REQUEST_HEADERS = {
  "Content-Type" => "application/vnd.api+json",
  "Accept" => "application/vnd.api+json"
}

# … prompt user for email and password

# Authenticate the user by creating a new token
auth = HTTParty.post("#{REQUEST_BASEURL}/tokens",
  basic_auth: { username: email, password: password },
  headers: REQUEST_HEADERS
)

# Get the newly created authentication token
if auth["errors"]
  # … handle invalid credentials
  exit
end

token = auth["data"]["attributes"]["token"]

# Check if they have a license for a specific product feature
licenses = HTTParty.get("#{REQUEST_BASEURL}/licenses?product=#{ENV['KEYGEN_PRODUCT_ID']}&policy=#{ENV['KEYGEN_FEATURE_POLICY_ID']}",
  headers: REQUEST_HEADERS.merge("Authorization" => "Bearer #{token}")
)

# Validate the first license we get back
if licenses["data"].empty?
  exit # User does not have a license for the feature
end

validation = HTTParty.get("#{REQUEST_BASEURL}/licenses/#{licenses['data'][0]['id']}/actions/validate",
  headers: REQUEST_HEADERS.merge("Authorization" => "Bearer #{token}")
)

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

define("REQUEST_BASEURL", "https://api.keygen.sh/v1/accounts/{$_ENV['KEYGEN_ACCOUNT_ID']}");
define("REQUEST_HEADERS", [
  "Content-Type" => "application/vnd.api+json",
  "Accept" => "application/vnd.api+json"
]);

// … prompt user for email and password

// Authenticate the user by creating a new token
$auth = json_decode(
  Requests::post(sprintf("%s/tokens", REQUEST_BASEURL),
    REQUEST_HEADERS,
    ["auth" => [$email, $password]]
  )->body
);

// Get the newly created authentication token
if (isset($auth["errors"])) {
  // … handle invalid credentials
  exit;
}

$token = $auth["data"]["attributes"]["token"];

// Check if they have a license for a specific product feature
$licenses = json_decode(
  Requests::get(sprintf("%s/licenses?product=%s&policy=%s", REQUEST_BASEURL, $_ENV["KEYGEN_PRODUCT_ID"], $_ENV["KEYGEN_FEATURE_POLICY_ID"]),
    REQUEST_HEADERS + ["Authorization" => "Bearer {$token}"]
  )->body
);

// Validate the first license we get back
if (!$licenses["data"]) {
  exit; // User does not have a license for the feature
}

$validation = json_decode(
  Requests::get(sprintf("%s/licenses/%s/actions/validate", REQUEST_BASEURL, $licenses["data"][0]["id"]),
    REQUEST_HEADERS + ["Authorization" => "Bearer {$token}"]
  )->body
);

if ($validation["meta"]["valid"]) {
  // Do something
} else {
  // Do something else
}

In-depth documentation on…

  • codeHow to easily implement Keygen into your product
  • syncHow to handle webhooks to integrate with your payment system
  • done_allHow to set up user registration and license verification
  • playlist_add_checkAnd of course, a full API reference with examples

Not ready to join? Stay updated.

FAQs

  • What is Keygen?

    Keygen is a powerful new SaaS offering in the software-licensing space built for small- to medium-sized software products. Keygen aims to disrupt the current market that is littered with unintuitive enterprise solutions by giving you the tools to handle licensing how you want using a simple JSON REST API.

  • 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.

  • What licensing models are supported?

    Keygen supports almost any licensing model: single machine-locked licenses, floating licenses with and without machine limits, feature-based licenses, product add-ons, limited pre-determined pool-based licenses, encrypted and unencrypted licenses, and even a combination of most of those. Keygen provides you the tools you need to handle licensing however you need for each of your products.

  • Does Keygen prevent sharing licenses?

    Keygen offers endpoints to track machine usage, and policies can be set to strict, which will ensure your users do not go over their machine limit. A license can be set to floating, which will allow the license 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 doing things such as: requiring a valid license for updates and support, etc.

  • What kind of pricing model will you offer?

    We'll likely be rolling out volume-based plans, based on number of products, users and licenses. We are still gathering usage stats and expenses from the beta, so things may change.

  • Will you offer on-premise API licensing?

    Yes. We're very interested in talking with companies that would rather host the Keygen licensing API in-house. Get in touch.

  • Will 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.

  • 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.

  • 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.

  • When will Keygen be released?

    Keygen is currently in closed beta. At this time there is not a concrete timeline for the full release. If you'd like to join the beta, please register and we'll send you further details.

  • Does Keygen handle payments?

    Since products handle payments in a variety of ways, 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.

  • 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.