Select programming language for code examples

linkReleases

Utilizing releases, you can manage the distribution of your products to licensed customers. Releases can be accessed according to the following rules:

  • Licenses: can access releases for their product, given the release was created prior to the license's expiry (if the license has an expiry), and that the license fulfills all of the release's entitlement contraints. Exact behavior will also depend on the product's distribution strategy, and the policy's expiration strategy.
  • Users: can access releases for their products, given the user has one or more associated licenses which fulfill the license requirements above.
  • Products: can access any release for their product.
  • Admins: can access any release for their account.

linkThe release object

Below you will find the various attributes for the release resource, as well as the release resource's relationships. Release versioning must follow the semver spec.

linkAttributes

  • linkdata.attributes.name

    string

    The human-readable name of the release. This can be used as an optional label.

  • linkdata.attributes.description

    string

    The description of the release. Useful for releases notes and the like.

  • linkdata.attributes.filename

    string

    The unique filename of the release. This value must be unique to the release's product relationship. We recommend including a version number in the filename when possible, to reduce conflicts. You may include prefixes e.g. prod-1/linux-1-0-0.tar.gz to differentiate product releases that share the same filename.

  • linkdata.attributes.filetype

    string

    The filetype of the release. This must match the filename's extension. When the filename does not contain an extension, filetype can be an arbitrary string, e.g. bin. When the release has multiple valid extensions, e.g. tar.gz, we recommend including the complete extension in the filetype to avoid conflicts (e.g. zip.gz and tar.gz would conflict if only gz was used).

  • linkdata.attributes.filesize

    integer

    The filesize of the release, in bytes.

  • linkdata.attributes.platform

    string

    The platform of the release. This may include an arch to differentiate multiple operating system architectures, e.g. darwin/amd64 and darwin/arm64.

  • linkdata.attributes.channel

    string

    The channel for the release. One of: stable, rc, beta, alpha, or dev.

  • linkdata.attributes.status

    stringread only

    The release's status, for filtering purposes and to ascertain overall status at-a-glance. A draft releases is one that does not yet have an uploaded artifact. A release is considered published when it has an uploaded artifact. One of: PUBLISHED, NOT_PUBLISHED, or YANKED.

  • linkdata.attributes.signature

    string

    The signature of the release. This can be an arbitrary string, utilized outside of Keygen for verification purposes. For example, Keygen's CLI uses Ed25519ph signatures.

  • linkdata.attributes.checksum

    string

    The checksum of the release. This can be an arbitrary string, utilized outside of Keygen for verification purposes. For example, Keygen's CLI uses SHA-512 checksums.

  • linkdata.attributes.downloads

    integerread only

    The number of times the release has been downloaded, not including upgrades.

  • linkdata.attributes.upgrades

    integerread only

    The number of times a licensee has upgraded to this release.

  • linkdata.attributes.version

    semver

    The version of the release. This must be a valid semantic version (semver) string. This value must be unique to the release's product, platform, channel and filetype relationship combination. The version may include prerelease and build tags.

  • linkdata.attributes.semver

    object<string, scalar>read only

    Object containing deconstructed key-value semver components.

  • linkdata.attributes.metadata

    object<string, scalar>

    Object containing release metadata. This can be used to store things such as hash checksums, e.g. sha-256 and sha-512, for integrity verification after download, or for release notes.

  • linkdata.attributes.created

    timestamp (ISO8601 format)read only

    When the release was created.

  • linkdata.attributes.updated

    timestamp (ISO8601 format)read only

    When the release was last updated.

  • linkdata.attributes.yanked

    timestamp (ISO8601 format)read only

    When the release was yanked.

linkRelationships

  • linkdata.relationships.account

    individual

    The account that the release belongs to.

  • linkdata.relationships.product

    individual

    The product that the release belongs to.

  • linkdata.relationships.constraints

    collection

    The constraints attached to the release.

  • linkdata.relationships.artifact

    individual

    The artifact for the release.

Example object

{
"data": {
"id": "30c64dcd-a74d-4f0d-8479-8745172a4817",
"type": "releases",
"attributes": {
"name": "Product v2",
"description": null,
"signature": "qqcVWX402un4PEoa+E1VMBfPaBJ1RSxwiGVwrFpGfbI7dulfIqUlovvm1X96m3G2Sjl8gXUDEr8gLEAbJuQQCQ",
"checksum": "lQ8T/qtGvsbqsDaXBqBMh6h2AGL8mTGI4XgLvLDYZA3EumRH8gIMjJ2l5lsO5L0LIvYVqWNXPVzTEp03H4yfZA",
"filename": "Product-2.0.0.dmg",
"filetype": "dmg",
"filesize": 209715200,
"platform": "darwin",
"channel": "stable",
"status": "PUBLISHED",
"downloads": 1337,
"upgrades": 42,
"version": "2.0.0",
"semver": {
"major": 2,
"minor": 0,
"patch": 0,
"prerelease": null,
"build": null
},
"metadata": {
"sha512": "36022a3f0b4bb6f3cdf57276867a210dc81f5c5b2215abf8a93c81ad18fa6bf0b1e36ee24ab7517c9474a1ad445a403d4612899687cabf591f938004df105011"
},
"created": "2021-05-14T19:54:16.289Z",
"updated": "2021-05-19T13:30:56.698Z",
"yanked": null
},
"relationships": {
"account": {
"links": {
"related": "/v1/accounts/{ACCOUNT}"
},
"data": {
"type": "accounts",
"id": "{ACCOUNT}"
}
},
"product": {
"links": {
"related": "/v1/accounts/{ACCOUNT}/releases/30c64dcd-a74d-4f0d-8479-8745172a4817/product"
},
"data": {
"type": "products",
"id": "652da162-cd35-4814-bd28-910a0df0dfad"
}
},
"constraints": {
"links": {
"related": "/v1/accounts/{ACCOUNT}/releases/30c64dcd-a74d-4f0d-8479-8745172a4817/constraints"
}
},
"artifact": {
"links": {
"related": "/v1/accounts/{ACCOUNT}/releases/30c64dcd-a74d-4f0d-8479-8745172a4817/artifact"
}
}
},
"links": {
"self": "/v1/accounts/{ACCOUNT}/releases/30c64dcd-a74d-4f0d-8479-8745172a4817"
}
}
}

linkCreate a release

Creates a new release resource.

Once a release is created, an artifact will still need to be uploaded before the release is available for download. You can upload an artifact through the release artifact relationship after creation.

linkAuthentication

  • linkBearer

    required

    An authentication token with privileges to manage the resource: either an admin, or the product it belongs to.

linkURL Parameters

  • link:account

    string, required

    The identifier (UUID) or slug of your Keygen account.

linkAttributes

  • linkdata.attributes.name

    string, optional

    The human-readable name of the release. This can be used as an optional label.

  • linkdata.attributes.description

    string, optional

    The description of the release. Useful for releases notes and the like.

  • linkdata.attributes.version

    semver, required

    The version of the release. This must be a valid semantic version (semver) string. This value must be unique to the release's product, platform, channel and filetype relationship combination. The version may include prerelease and build tags.

  • linkdata.attributes.filename

    string, required

    The unique filename of the release. This value must be unique to the release's product relationship. We recommend including a version number in the filename when possible, to reduce conflicts. You may include prefixes e.g. prod-1/linux-1-0-0.tar.gz to differentiate product releases that share the same filename.

  • linkdata.attributes.filetype

    string, required

    The filetype of the release. This must match the filename's extension. When the filename does not contain an extension, filetype can be an arbitrary string, e.g. bin. When the release has multiple valid extensions, e.g. tar.gz, we recommend including the complete extension in the filetype to avoid conflicts (e.g. zip.gz and tar.gz would conflict if only gz was used).

  • linkdata.attributes.filesize

    integer, optional

    The filesize of the release, in bytes.

  • linkdata.attributes.platform

    string, required

    The platform of the release. This may include an arch to differentiate multiple operating system architectures, e.g. darwin/amd64 and darwin/arm64.

  • linkdata.attributes.channel

    string, required

    The channel for the release. One of: stable, rc, beta, alpha, or dev. For prereleases, i.e. non-stable, the channel must match the version's prerelease tag.

  • linkdata.attributes.signature

    string, optional

    The signature of the release. This can be an arbitrary string, utilized outside of Keygen for verification purposes. For example, Keygen's CLI uses Ed25519ph signatures.

  • linkdata.attributes.checksum

    string, optional

    The checksum of the release. This can be an arbitrary string, utilized outside of Keygen for verification purposes. For example, Keygen's CLI uses SHA-512 checksums.

  • linkdata.attributes.metadata

    object<string, scalar>, optional

    Object containing release metadata. This can be used to store things such as hash checksums, e.g. sha-256 and sha-512, for integrity verification after download, or for release notes.

linkRelationships

  • linkdata.relationships.product

    linkage<product>, required

    The product the release is for.

  • linkdata.relationships.constraints

    array<constraint>, optional

    The constraints for the release. Constraints can be used to require certain license entitlements in order to access a release, e.g. ACCESS_V1 and ACCESS_V2. If the licensee lacks an entitlement constraint, access will be denied.

linkReturns

A 201 Created response will be returned along with the new release object.

Upon error, an errors object will be returned along with an HTTP status code indicating the type of error. When an error occurs, the data property will not be included.

Definition

https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases

Example request

const fetch = require("node-fetch")
 
const response = await fetch("https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases", {
method: "POST",
headers: {
"Authorization": "Bearer {TOKEN}",
"Content-Type": "application/vnd.api+json",
"Accept": "application/vnd.api+json"
},
body: JSON.stringify({
"data": {
"type": "release",
"attributes": {
"name": "Product v2-alpha1",
"filename": "Product-2.0.0-alpha1.dmg",
"filesize": 209715200,
"filetype": "dmg",
"version": "2.0.0-alpha1",
"platform": "darwin",
"channel": "alpha",
"metadata": {
"sha512": "36022a3f0b4bb6f3cdf57276867a210dc81f5c5b2215abf8a93c81ad18fa6bf0b1e36ee24ab7517c9474a1ad445a403d4612899687cabf591f938004df105011"
}
},
"relationships": {
"product": {
"data": {
"type": "product",
"id": "855ef427-6f68-4153-ab88-e63c631014c3"
}
},
"constraints": {
"data": [
{
"type": "constraint",
"relationships": {
"entitlement": {
"data": { "type": "entitlement", "id": "2f9397b0-bbde-4219-a761-1307f338261f" }
}
}
},
{
"type": "constraint",
"relationships": {
"entitlement": {
"data": { "type": "entitlement", "id": "481cc294-3f91-4efe-b471-90d14ecd5887" }
}
}
}
]
}
}
}
})
})
 
const { data, errors } = await response.json()
import requests
import json
 
res = requests.post(
"https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases",
headers={
"Content-Type": "application/vnd.api+json",
"Accept": "application/vnd.api+json",
"Authorization": "Bearer {TOKEN}"
},
data=json.dumps({
"data": {
"type": "release",
"attributes": {
"name": "Product v2-alpha1",
"filename": "Product-2.0.0-alpha1.dmg",
"filesize": 209715200,
"filetype": "dmg",
"version": "2.0.0-alpha1",
"platform": "darwin",
"channel": "alpha",
"metadata": {
"sha512": "36022a3f0b4bb6f3cdf57276867a210dc81f5c5b2215abf8a93c81ad18fa6bf0b1e36ee24ab7517c9474a1ad445a403d4612899687cabf591f938004df105011"
}
},
"relationships": {
"product": {
"data": {
"type": "product",
"id": "855ef427-6f68-4153-ab88-e63c631014c3"
}
},
"constraints": {
"data": [
{
"type": "constraint",
"relationships": {
"entitlement": {
"data": { "type": "entitlement", "id": "2f9397b0-bbde-4219-a761-1307f338261f" }
}
}
},
{
"type": "constraint",
"relationships": {
"entitlement": {
"data": { "type": "entitlement", "id": "481cc294-3f91-4efe-b471-90d14ecd5887" }
}
}
}
]
}
}
}
})
).json()
import SwiftyJSON
import Alamofire
 
Alamofire.request("https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases",
method: .post,
headers: [
"Content-Type": "application/vnd.api+json",
"Accept": "application/vnd.api+json",
"Authorization": "Bearer {TOKEN}"
],
parameters: [
"data": [
"type": "release",
"attributes": [
"name": "Product v2-alpha1",
"filename": "Product-2.0.0-alpha1.dmg",
"filesize": 209715200,
"filetype": "dmg",
"version": "2.0.0-alpha1",
"platform": "darwin",
"channel": "alpha",
"metadata": [
"sha512": "36022a3f0b4bb6f3cdf57276867a210dc81f5c5b2215abf8a93c81ad18fa6bf0b1e36ee24ab7517c9474a1ad445a403d4612899687cabf591f938004df105011"
]
],
"relationships": [
"product": [
"data": [
"type": "product",
"id": "855ef427-6f68-4153-ab88-e63c631014c3"
]
],
"constraints": [
"data": [
[
"type": "constraint",
"relationships": [
"entitlement": [
"data": ["type": "entitlement", "id": "2f9397b0-bbde-4219-a761-1307f338261f"]
]
]
],
[
"type": "constraint",
"relationships": [
"entitlement": [
"data": ["type": "entitlement", "id": "481cc294-3f91-4efe-b471-90d14ecd5887"]
]
]
]
]
]
]
]
],
encoding: JSONEncoding.default
).responseJSON { response in
let json = JSON(data: response.data!)
}
using RestSharp;
 
var client = new RestClient("https://api.keygen.sh/v1/accounts/{ACCOUNT}");
var request = new RestRequest("releases", Method.POST);
 
request.AddHeader("Content-Type", "application/vnd.api+json");
request.AddHeader("Accept", "application/vnd.api+json");
request.AddHeader("Authorization", "Bearer {TOKEN}");
 
request.AddJsonBody(new {
data = new {
type = "releases",
attributes = new {
name = "Product v2-alpha1",
filename = "Product-2.0.0-alpha1.dmg",
filesize = 209715200,
filetype = "dmg",
version = "2.0.0-alpha1",
platform = "darwin",
channel = "alpha",
metadata = new {
sha512 = "36022a3f0b4bb6f3cdf57276867a210dc81f5c5b2215abf8a93c81ad18fa6bf0b1e36ee24ab7517c9474a1ad445a403d4612899687cabf591f938004df105011"
}
},
relationships = new {
product = new {
data = new { type = "products", id = "855ef427-6f68-4153-ab88-e63c631014c3" }
},
constraints = new {
data = [
new {
type = "constraint",
relationships = new {
entitlement = new {
data = new { type = "entitlement", id = "2f9397b0-bbde-4219-a761-1307f338261f" }
}
}
},
new {
type = "constraint",
relationships = new {
entitlement = new {
data = new { type = "entitlement", id = "481cc294-3f91-4efe-b471-90d14ecd5887" }
}
}
}
]
}
}
}
});
 
var response = client.Execute(request);
import com.mashape.unirest.http.exceptions.*
import com.mashape.unirest.http.*
import org.json.*
 
val body = JSONObject(mapOf(
"data" to mapOf(
"type" to "releases",
"attributes" to mapOf(
"name" to "Product v2-alpha1",
"filename" to "Product-2.0.0-alpha1.dmg",
"filesize" to 209715200,
"filetype" to "dmg",
"version" to "2.0.0-alpha1",
"platform" to "darwin",
"channel" to "alpha",
"metadata" to mapOf(
"sha512" to "36022a3f0b4bb6f3cdf57276867a210dc81f5c5b2215abf8a93c81ad18fa6bf0b1e36ee24ab7517c9474a1ad445a403d4612899687cabf591f938004df105011"
)
),
"relationships" to mapOf(
"product" to mapOf(
"data" to mapOf("type" to "products", "id" to "855ef427-6f68-4153-ab88-e63c631014c3")
)
)
)
))
 
val res = Unirest.post("https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases")
.header("Authorization", "Bearer {TOKEN}")
.header("Content-Type", "application/vnd.api+json")
.header("Accept", "application/vnd.api+json")
.body(body)
.asJson()
import com.mashape.unirest.http.exceptions.*;
import com.mashape.unirest.http.*;
import org.json.*;
 
import static java.util.Map.ofEntries;
import static java.util.Map.entry;
 
JSONObject body = new JSONObject(ofEntries(
entry("data", ofEntries(
entry("type", "releases"),
entry("attributes", ofEntries(
entry("name" ,"Product v2-alpha1"),
entry("filename", "Product-2.0.0-alpha1.dmg"),
entry("filesize", 209715200),
entry("filetype", "dmg"),
entry("version", "2.0.0-alpha1"),
entry("platform", "darwin"),
entry("channel", "alpha")
),
entry("relationships", ofEntries(
entry("product", ofEntries(
entry("data", ofEntries(
entry("type", "products"),
entry("id", "855ef427-6f68-4153-ab88-e63c631014c3")
))
))
))
))
));
 
HttpResponse<JsonNode> res = Unirest.post("https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases")
.header("Authorization", "Bearer {TOKEN}")
.header("Content-Type", "application/vnd.api+json")
.header("Accept", "application/vnd.api+json")
.body(body)
.asJson();
#include <iostream>
#include <string>
#include <cpprest/http_client.h>
#include <cpprest/filestream.h>
 
using namespace std;
using namespace web;
using namespace web::http;
using namespace web::http::client;
using namespace web::json;
using namespace utility;
 
http_client client("https://api.keygen.sh/v1/accounts/{ACCOUNT}");
http_request req;
 
value attrs;
attrs["name"] = value::string("Product v2-alpha1");
attrs["filename"] = value::string("Product-2.0.0-alpha1.dmg");
attrs["filesize"] = value::number(209715200);
attrs["filetype"] = value::string("dmg");
attrs["version"] = value::string("2.0.0-alpha1");
attrs["platform"] = value::string("darwin");
attrs["channel"] = value::string("alpha");
 
value product_linkage;
product_linkage["type"] = value::string("products");
product_linkage["id"] = value::string("855ef427-6f68-4153-ab88-e63c631014c3");
 
value product;
product["data"] = product_linkage;
 
value rels;
rels["product"] = product;
 
value data;
data["type"] = value::string("releases");
data["attributes"] = attrs;
data["relationships"] = rels;
 
value body;
body["data"] = data;
 
req.headers().add("Authorization", "Bearer {TOKEN}");
req.headers().add("Content-Type", "application/vnd.api+json");
req.headers().add("Accept", "application/json");
 
req.set_request_uri("/releases");
req.set_method(methods::POST);
req.set_body(body.serialize());
 
client.request(req)
.then([](http_response res)
{
auto data = res.extract_json().get();
})
.wait();
curl -X POST https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases \
-H 'Authorization: Bearer {TOKEN}' \
-H 'Content-Type: application/vnd.api+json' \
-H 'Accept: application/vnd.api+json' \
-d '{
"data": {
"type": "release",
"attributes": {
"name": "Product v2-alpha1",
"filename": "Product-2.0.0-alpha1.dmg",
"filesize": 209715200,
"filetype": "dmg",
"version": "2.0.0-alpha1",
"platform": "darwin",
"channel": "alpha",
"metadata": {
"sha512": "36022a3f0b4bb6f3cdf57276867a210dc81f5c5b2215abf8a93c81ad18fa6bf0b1e36ee24ab7517c9474a1ad445a403d4612899687cabf591f938004df105011"
}
},
"relationships": {
"product": {
"data": {
"type": "product",
"id": "855ef427-6f68-4153-ab88-e63c631014c3"
}
}
}
}
}'

Example response / 201 Created

{
"data": {
"id": "30c64dcd-a74d-4f0d-8479-8745172a4817",
"type": "releases",
"attributes": {
"name": "Product v2-alpha1",
"description": null,
"signature": null,
"checksum": null,
"filename": "Product-2.0.0-alpha1.dmg",
"filetype": "dmg",
"filesize": 209715200,
"platform": "darwin",
"channel": "alpha",
"status": "NOT_PUBLISHED",
"downloads": 0,
"upgrades": 0,
"version": "2.0.0-alpha1",
"semver": {
"major": 2,
"minor": 0,
"patch": 0,
"prerelease": "alpha1",
"build": null
},
"metadata": {
"sha512": "36022a3f0b4bb6f3cdf57276867a210dc81f5c5b2215abf8a93c81ad18fa6bf0b1e36ee24ab7517c9474a1ad445a403d4612899687cabf591f938004df105011"
},
"created": "2021-05-14T19:54:16.289Z",
"updated": "2021-05-19T13:30:56.698Z",
"yanked": null
},
"relationships": {
"account": {
"links": {
"related": "/v1/accounts/{ACCOUNT}"
},
"data": {
"type": "accounts",
"id": "{ACCOUNT}"
}
},
"product": {
"links": {
"related": "/v1/accounts/{ACCOUNT}/releases/30c64dcd-a74d-4f0d-8479-8745172a4817/product"
},
"data": {
"type": "products",
"id": "652da162-cd35-4814-bd28-910a0df0dfad"
}
},
"constraints": {
"links": {
"related": "/v1/accounts/{ACCOUNT}/releases/30c64dcd-a74d-4f0d-8479-8745172a4817/constraints"
}
},
"artifact": {
"links": {
"related": "/v1/accounts/{ACCOUNT}/releases/30c64dcd-a74d-4f0d-8479-8745172a4817/artifact"
}
}
},
"links": {
"self": "/v1/accounts/{ACCOUNT}/releases/30c64dcd-a74d-4f0d-8479-8745172a4817"
}
}
}

linkUpsert a release

Upserts a release resource. This is useful when your releases share a common filename, such as latest.yml, and you want to publish releases idempotently, without worrying about conflicts with previous versions of the release. Detailed behavior is below:

  • When a release with the same filename exists for the given product: the release will be updated with the supplied attributes and constraints.
  • When the release does not exist: a new release will be created.

This operation is not atomic. Highly concurrent upserts for the same release may conflict with eachother, but at least 1 will succeed.

Once a release is upserted, a new artifact will need to be uploaded. The old artifact will continue to be available until a new artifact replaces it. You can upload a new artifact through the release artifact relationship after upsert.

linkAuthentication

  • linkBearer

    required

    An authentication token with privileges to manage the resource: either an admin, or the product it belongs to.

linkURL Parameters

  • link:account

    string, required

    The identifier (UUID) or slug of your Keygen account.

linkAttributes

  • linkdata.attributes.name

    string, optional

    The human-readable name of the release. This can be used as an optional label.

  • linkdata.attributes.description

    string, optional

    The description of the release. Useful for releases notes and the like.

  • linkdata.attributes.version

    semver, required

    The version of the release. This must be a valid semantic version (semver) string. This value must be unique to the release's product, platform, channel and filetype relationship combination. The version may include prerelease and build tags.

  • linkdata.attributes.filename

    string, required

    The unique filename of the release. This value must be unique to the release's product relationship. We recommend including a version number in the filename when possible, to reduce conflicts. You may include prefixes e.g. prod-1/linux-1-0-0.tar.gz to differentiate product releases that share the same filename.

  • linkdata.attributes.filetype

    string, required

    The filetype of the release. This must match the filename's extension. When the filename does not contain an extension, filetype can be an arbitrary string, e.g. bin. When the release has multiple valid extensions, e.g. tar.gz, we recommend including the complete extension in the filetype to avoid conflicts (e.g. zip.gz and tar.gz would conflict if only gz was used).

  • linkdata.attributes.filesize

    integer, optional

    The filesize of the release, in bytes.

  • linkdata.attributes.platform

    string, required

    The platform of the release. This may include an arch to differentiate multiple operating system architectures, e.g. darwin/amd64 and darwin/arm64.

  • linkdata.attributes.channel

    string, required

    The channel for the release. One of: stable, rc, beta, alpha, or dev. For prereleases, i.e. non-stable, the channel must match the version's prerelease tag.

  • linkdata.attributes.signature

    string, optional

    The signature of the release. This can be an arbitrary string, utilized outside of Keygen for verification purposes. For example, Keygen's CLI uses Ed25519ph signatures.

  • linkdata.attributes.checksum

    string, optional

    The checksum of the release. This can be an arbitrary string, utilized outside of Keygen for verification purposes. For example, Keygen's CLI uses SHA-512 checksums.

  • linkdata.attributes.metadata

    object<string, scalar>, optional

    Object containing release metadata. This can be used to store things such as hash checksums, e.g. sha-256 and sha-512, for integrity verification after download, or for release notes.

linkRelationships

  • linkdata.relationships.product

    linkage<product>, required

    The product the release is for.

  • linkdata.relationships.constraints

    array<constraint>, optional

    The constraints for the release. Constraints can be used to require certain license entitlements in order to access a release, e.g. ACCESS_V1 and ACCESS_V2. If the licensee lacks an entitlement constraint, access will be denied.

linkReturns

If the release already existed, i.e. there was a filename conflict, a 200 OK response will be returned along with the updated release object, otherwise a 201 Created response will be returned with the new release object.

Upon error, an errors object will be returned along with an HTTP status code indicating the type of error. When an error occurs, the data property will not be included.

Definition

https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases

Example request

const fetch = require("node-fetch")
 
const response = await fetch("https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases", {
method: "PUT",
headers: {
"Authorization": "Bearer {TOKEN}",
"Content-Type": "application/vnd.api+json",
"Accept": "application/vnd.api+json"
},
body: JSON.stringify({
"data": {
"type": "release",
"attributes": {
"filename": "latest-mac.yml",
"filetype": "yml",
"filesize": 593,
"version": "2.0.0",
"platform": "darwin",
"channel": "stable",
"metadata": {
"sha512": "36022a3f0b4bb6f3cdf57276867a210dc81f5c5b2215abf8a93c81ad18fa6bf0b1e36ee24ab7517c9474a1ad445a403d4612899687cabf591f938004df105011"
}
},
"relationships": {
"product": {
"data": {
"type": "product",
"id": "855ef427-6f68-4153-ab88-e63c631014c3"
}
},
"constraints": {
"data": [
{
"type": "constraint",
"relationships": {
"entitlement": {
"data": { "type": "entitlement", "id": "2f9397b0-bbde-4219-a761-1307f338261f" }
}
}
},
{
"type": "constraint",
"relationships": {
"entitlement": {
"data": { "type": "entitlement", "id": "481cc294-3f91-4efe-b471-90d14ecd5887" }
}
}
}
]
}
}
}
})
})
 
const { data, errors } = await response.json()
import requests
import json
 
res = requests.post(
"https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases",
headers={
"Content-Type": "application/vnd.api+json",
"Accept": "application/vnd.api+json",
"Authorization": "Bearer {TOKEN}"
},
data=json.dumps({
"data": {
"type": "release",
"attributes": {
"filename": "latest-mac.yml",
"filetype": "yml",
"filesize": 593,
"version": "2.0.0",
"platform": "darwin",
"channel": "stable",
"metadata": {
"sha512": "36022a3f0b4bb6f3cdf57276867a210dc81f5c5b2215abf8a93c81ad18fa6bf0b1e36ee24ab7517c9474a1ad445a403d4612899687cabf591f938004df105011"
}
},
"relationships": {
"product": {
"data": {
"type": "product",
"id": "855ef427-6f68-4153-ab88-e63c631014c3"
}
},
"constraints": {
"data": [
{
"type": "constraint",
"relationships": {
"entitlement": {
"data": { "type": "entitlement", "id": "2f9397b0-bbde-4219-a761-1307f338261f" }
}
}
},
{
"type": "constraint",
"relationships": {
"entitlement": {
"data": { "type": "entitlement", "id": "481cc294-3f91-4efe-b471-90d14ecd5887" }
}
}
}
]
}
}
}
})
).json()
import SwiftyJSON
import Alamofire
 
Alamofire.request("https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases",
method: .post,
headers: [
"Content-Type": "application/vnd.api+json",
"Accept": "application/vnd.api+json",
"Authorization": "Bearer {TOKEN}"
],
parameters: [
"data": [
"type": "release",
"attributes": [
"filename": "latest-mac.yml",
"filetype": "yml",
"filesize": 593,
"version": "2.0.0",
"platform": "darwin",
"channel": "stable",
"metadata": [
"sha512": "36022a3f0b4bb6f3cdf57276867a210dc81f5c5b2215abf8a93c81ad18fa6bf0b1e36ee24ab7517c9474a1ad445a403d4612899687cabf591f938004df105011"
]
],
"relationships": [
"product": [
"data": [
"type": "product",
"id": "855ef427-6f68-4153-ab88-e63c631014c3"
]
],
"constraints": [
"data": [
[
"type": "constraint",
"relationships": [
"entitlement": [
"data": ["type": "entitlement", "id": "2f9397b0-bbde-4219-a761-1307f338261f"]
]
]
],
[
"type": "constraint",
"relationships": [
"entitlement": [
"data": ["type": "entitlement", "id": "481cc294-3f91-4efe-b471-90d14ecd5887"]
]
]
]
]
]
]
]
],
encoding: JSONEncoding.default
).responseJSON { response in
let json = JSON(data: response.data!)
}
using RestSharp;
 
var client = new RestClient("https://api.keygen.sh/v1/accounts/{ACCOUNT}");
var request = new RestRequest("releases", Method.PUT);
 
request.AddHeader("Content-Type", "application/vnd.api+json");
request.AddHeader("Accept", "application/vnd.api+json");
request.AddHeader("Authorization", "Bearer {TOKEN}");
 
request.AddJsonBody(new {
data = new {
type = "releases",
attributes = new {
filename = "latest-mac.yml",
filetype = "yml",
filesize = 593,
version = "2.0.0",
platform = "darwin",
channel = "stable",
metadata = new {
sha512 = "36022a3f0b4bb6f3cdf57276867a210dc81f5c5b2215abf8a93c81ad18fa6bf0b1e36ee24ab7517c9474a1ad445a403d4612899687cabf591f938004df105011"
}
},
relationships = new {
product = new {
data = new { type = "products", id = "855ef427-6f68-4153-ab88-e63c631014c3" }
},
constraints = new {
data = [
new {
type = "constraint",
relationships = new {
entitlement = new {
data = new { type = "entitlement", id = "2f9397b0-bbde-4219-a761-1307f338261f" }
}
}
},
new {
type = "constraint",
relationships = new {
entitlement = new {
data = new { type = "entitlement", id = "481cc294-3f91-4efe-b471-90d14ecd5887" }
}
}
}
]
}
}
}
});
 
var response = client.Execute(request);
import com.mashape.unirest.http.exceptions.*
import com.mashape.unirest.http.*
import org.json.*
 
val body = JSONObject(mapOf(
"data" to mapOf(
"type" to "releases",
"attributes" to mapOf(
"filename" to "latest-mac.yml",
"filetype" to "yml",
"filesize" to 593,
"version" to "2.0.0",
"platform" to "darwin",
"channel" to "stable",
"metadata" to mapOf(
"sha512" to "36022a3f0b4bb6f3cdf57276867a210dc81f5c5b2215abf8a93c81ad18fa6bf0b1e36ee24ab7517c9474a1ad445a403d4612899687cabf591f938004df105011"
)
),
"relationships" to mapOf(
"product" to mapOf(
"data" to mapOf("type" to "products", "id" to "855ef427-6f68-4153-ab88-e63c631014c3")
)
)
)
))
 
val res = Unirest.post("https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases")
.header("Authorization", "Bearer {TOKEN}")
.header("Content-Type", "application/vnd.api+json")
.header("Accept", "application/vnd.api+json")
.body(body)
.asJson()
import com.mashape.unirest.http.exceptions.*;
import com.mashape.unirest.http.*;
import org.json.*;
 
import static java.util.Map.ofEntries;
import static java.util.Map.entry;
 
JSONObject body = new JSONObject(ofEntries(
entry("data", ofEntries(
entry("type", "releases"),
entry("attributes", ofEntries(
entry("filename", "latest-mac.yml"),
entry("filetype", "yml"),
entry("filesize", 593),
entry("version", "2.0.0"),
entry("platform", "darwin"),
entry("channel", "stable")
),
entry("relationships", ofEntries(
entry("product", ofEntries(
entry("data", ofEntries(
entry("type", "products"),
entry("id", "855ef427-6f68-4153-ab88-e63c631014c3")
))
))
))
))
));
 
HttpResponse<JsonNode> res = Unirest.post("https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases")
.header("Authorization", "Bearer {TOKEN}")
.header("Content-Type", "application/vnd.api+json")
.header("Accept", "application/vnd.api+json")
.body(body)
.asJson();
#include <iostream>
#include <string>
#include <cpprest/http_client.h>
#include <cpprest/filestream.h>
 
using namespace std;
using namespace web;
using namespace web::http;
using namespace web::http::client;
using namespace web::json;
using namespace utility;
 
http_client client("https://api.keygen.sh/v1/accounts/{ACCOUNT}");
http_request req;
 
value attrs;
attrs["filename"] = value::string("latest-mac.yml");
attrs["filetype"] = value::string("yml");
attrs["filesize"] = value::number(593);
attrs["version"] = value::string("2.0.0");
attrs["platform"] = value::string("darwin");
attrs["channel"] = value::string("stable");
 
value product_linkage;
product_linkage["type"] = value::string("products");
product_linkage["id"] = value::string("855ef427-6f68-4153-ab88-e63c631014c3");
 
value product;
product["data"] = product_linkage;
 
value rels;
rels["product"] = product;
 
value data;
data["type"] = value::string("licenses");
data["attributes"] = attrs;
data["relationships"] = rels;
 
value body;
body["data"] = data;
 
req.headers().add("Authorization", "Bearer {TOKEN}");
req.headers().add("Content-Type", "application/vnd.api+json");
req.headers().add("Accept", "application/json");
 
req.set_request_uri("/releases");
req.set_method(methods::PUT);
req.set_body(body.serialize());
 
client.request(req)
.then([](http_response res)
{
auto data = res.extract_json().get();
})
.wait();
curl -X PUT https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases \
-H 'Authorization: Bearer {TOKEN}' \
-H 'Content-Type: application/vnd.api+json' \
-H 'Accept: application/vnd.api+json' \
-d '{
"data": {
"type": "release",
"attributes": {
"filename": "latest-mac.yml",
"filetype": "yml",
"filesize": 593,
"version": "2.0.0",
"platform": "darwin",
"channel": "stable",
"metadata": {
"sha512": "36022a3f0b4bb6f3cdf57276867a210dc81f5c5b2215abf8a93c81ad18fa6bf0b1e36ee24ab7517c9474a1ad445a403d4612899687cabf591f938004df105011"
}
},
"relationships": {
"product": {
"data": {
"type": "product",
"id": "855ef427-6f68-4153-ab88-e63c631014c3"
}
},
"constraints": {
"data": [
{
"type": "constraint",
"relationships": {
"entitlement": {
"data": { "type": "entitlement", "id": "2f9397b0-bbde-4219-a761-1307f338261f" }
}
}
}
]
}
}
}
}'

Example response / 200 OK

{
"data": {
"id": "30c64dcd-a74d-4f0d-8479-8745172a4817",
"type": "releases",
"attributes": {
"name": null,
"description": null,
"signature": "qqcVWX402un4PEoa+E1VMBfPaBJ1RSxwiGVwrFpGfbI7dulfIqUlovvm1X96m3G2Sjl8gXUDEr8gLEAbJuQQCQ",
"checksum": "lQ8T/qtGvsbqsDaXBqBMh6h2AGL8mTGI4XgLvLDYZA3EumRH8gIMjJ2l5lsO5L0LIvYVqWNXPVzTEp03H4yfZA",
"filename": "latest-mac.yml",
"filetype": "yml",
"filesize": 593,
"platform": "darwin",
"channel": "stable",
"status": "PUBLISHED",
"downloads": 0,
"upgrades": 0,
"version": "2.0.0",
"semver": {
"major": 2,
"minor": 0,
"patch": 0,
"prerelease": null,
"build": null
},
"metadata": {
"sha512": "36022a3f0b4bb6f3cdf57276867a210dc81f5c5b2215abf8a93c81ad18fa6bf0b1e36ee24ab7517c9474a1ad445a403d4612899687cabf591f938004df105011"
},
"created": "2021-05-14T19:54:16.289Z",
"updated": "2021-05-19T13:30:56.698Z",
"yanked": null
},
"relationships": {
"account": {
"links": {
"related": "/v1/accounts/{ACCOUNT}"
},
"data": {
"type": "accounts",
"id": "{ACCOUNT}"
}
},
"product": {
"links": {
"related": "/v1/accounts/{ACCOUNT}/releases/30c64dcd-a74d-4f0d-8479-8745172a4817/product"
},
"data": {
"type": "products",
"id": "652da162-cd35-4814-bd28-910a0df0dfad"
}
},
"constraints": {
"links": {
"related": "/v1/accounts/{ACCOUNT}/releases/30c64dcd-a74d-4f0d-8479-8745172a4817/constraints"
}
},
"artifact": {
"links": {
"related": "/v1/accounts/{ACCOUNT}/releases/30c64dcd-a74d-4f0d-8479-8745172a4817/artifact"
}
}
},
"links": {
"self": "/v1/accounts/{ACCOUNT}/releases/30c64dcd-a74d-4f0d-8479-8745172a4817"
}
}
}

linkRetrieve a release

Retrieves the details of an existing release.

linkAuthentication

  • linkBearer

    optional

    An authentication token with privileges to read the release: either an admin, the product it belongs to, an entitled license (via an activation token), or a user with an entitled license. If the product's distribution strategy is OPEN, no authentication is required.

linkURL Parameters

  • link:account

    string, required

    The identifier (UUID) or slug of your Keygen account.

  • link:release

    string, required

    The identifier (UUID) of the release to be retrieved.

linkReturns

A 200 OK response will be returned along with a release object.

Upon error, an errors object will be returned along with an HTTP status code indicating the type of error. When an error occurs, the data property will not be included.

Definition

https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/{RELEASE}

Example request

const fetch = require("node-fetch")
 
const response = await fetch("https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/30c64dcd-a74d-4f0d-8479-8745172a4817", {
method: "GET",
headers: {
"Authorization": "Bearer {TOKEN}",
"Accept": "application/vnd.api+json"
}
})
 
const { data, errors } = await response.json()
import requests
import json
 
res = requests.get(
"https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/30c64dcd-a74d-4f0d-8479-8745172a4817",
headers={
"Authorization": "Bearer {TOKEN}",
"Accept": "application/vnd.api+json"
}
).json()
import SwiftyJSON
import Alamofire
 
Alamofire.request("https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/30c64dcd-a74d-4f0d-8479-8745172a4817",
headers: [
"Authorization": "Bearer {TOKEN}",
"Accept": "application/vnd.api+json"
]
).responseJSON { response in
let json = JSON(data: response.data!)
}
using RestSharp;
 
var client = new RestClient("https://api.keygen.sh/v1/accounts/{ACCOUNT}");
var request = new RestRequest(
"releases/30c64dcd-a74d-4f0d-8479-8745172a4817",
Method.GET
);
 
request.AddHeader("Authorization", "Bearer {TOKEN}");
request.AddHeader("Accept", "application/vnd.api+json");
 
var response = client.Execute(request);
import com.mashape.unirest.http.exceptions.*
import com.mashape.unirest.http.*
 
val res = Unirest.get("https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/30c64dcd-a74d-4f0d-8479-8745172a4817")
.header("Authorization", "Bearer {TOKEN}")
.header("Accept", "application/vnd.api+json")
.asJson()
import com.mashape.unirest.http.exceptions.*;
import com.mashape.unirest.http.*;
 
HttpResponse<JsonNode> res = Unirest.get("https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/30c64dcd-a74d-4f0d-8479-8745172a4817")
.header("Authorization", "Bearer {TOKEN}")
.header("Accept", "application/vnd.api+json")
.asJson();
#include <iostream>
#include <string>
#include <cpprest/http_client.h>
#include <cpprest/filestream.h>
 
using namespace std;
using namespace web;
using namespace web::http;
using namespace web::http::client;
using namespace utility;
 
http_client client("https://api.keygen.sh/v1/accounts/{ACCOUNT}");
http_request req;
 
req.headers().add("Authorization", "Bearer {TOKEN}");
req.headers().add("Accept", "application/json");
 
req.set_request_uri("/releases/30c64dcd-a74d-4f0d-8479-8745172a4817");
req.set_method(methods::GET);
 
client.request(req)
.then([](http_response res) {
auto data = res.extract_json().get();
})
.wait();
curl https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/30c64dcd-a74d-4f0d-8479-8745172a4817 \
-H 'Authorization: Bearer {TOKEN}' \
-H 'Accept: application/vnd.api+json'

Example response / 200 OK

{
"data": {
"id": "30c64dcd-a74d-4f0d-8479-8745172a4817",
"type": "releases",
"attributes": {
"name": "Product v1.0.0",
"description": null,
"signature": "qqcVWX402un4PEoa+E1VMBfPaBJ1RSxwiGVwrFpGfbI7dulfIqUlovvm1X96m3G2Sjl8gXUDEr8gLEAbJuQQCQ",
"checksum": "lQ8T/qtGvsbqsDaXBqBMh6h2AGL8mTGI4XgLvLDYZA3EumRH8gIMjJ2l5lsO5L0LIvYVqWNXPVzTEp03H4yfZA",
"filename": "Product-Windows-1.0.0.zip",
"filetype": "zip",
"filesize": 209715200,
"platform": "win32",
"channel": "stable",
"status": "PUBLISHED",
"downloads": 9000,
"upgrades": 42,
"version": "1.0.0+build.1626813051",
"semver": {
"major": 1,
"minor": 0,
"patch": 0,
"prerelease": null,
"build": "build.1626813051"
},
"metadata": {
"sha512": "36022a3f0b4bb6f3cdf57276867a210dc81f5c5b2215abf8a93c81ad18fa6bf0b1e36ee24ab7517c9474a1ad445a403d4612899687cabf591f938004df105011"
},
"created": "2021-05-14T19:54:16.289Z",
"updated": "2021-05-19T13:30:56.698Z",
"yanked": null
},
"relationships": {
"account": {
"links": {
"related": "/v1/accounts/{ACCOUNT}"
},
"data": {
"type": "accounts",
"id": "{ACCOUNT}"
}
},
"product": {
"links": {
"related": "/v1/accounts/{ACCOUNT}/releases/30c64dcd-a74d-4f0d-8479-8745172a4817/product"
},
"data": {
"type": "products",
"id": "652da162-cd35-4814-bd28-910a0df0dfad"
}
},
"constraints": {
"links": {
"related": "/v1/accounts/{ACCOUNT}/releases/30c64dcd-a74d-4f0d-8479-8745172a4817/constraints"
}
},
"artifact": {
"links": {
"related": "/v1/accounts/{ACCOUNT}/releases/30c64dcd-a74d-4f0d-8479-8745172a4817/artifact"
}
}
},
"links": {
"self": "/v1/accounts/{ACCOUNT}/releases/30c64dcd-a74d-4f0d-8479-8745172a4817"
}
}
}

linkUpdate a release

Updates the specified release resource by setting the values of the parameters passed. Any parameters not provided will be left unchanged.

linkAuthentication

  • linkBearer

    required

    An authentication token with privileges to manage the resource: either an admin, or the product it belongs to.

linkURL Parameters

  • link:account

    string, required

    The identifier (UUID) or slug of your Keygen account.

  • link:release

    string, required

    The identifier (UUID) of the release to be updated.

linkAttributes

  • linkdata.attributes.name

    string, optional

    The human-readable name of the release. This can be used as an optional label.

  • linkdata.attributes.description

    string, optional

    The description of the release. Useful for releases notes and the like.

  • linkdata.attributes.filesize

    integer, optional

    The filesize of the release, in bytes.

  • linkdata.attributes.signature

    string, optional

    The signature of the release. This can be an arbitrary string, utilized outside of Keygen for verification purposes. For example, Keygen's CLI uses Ed25519ph signatures.

  • linkdata.attributes.checksum

    string, optional

    The checksum of the release. This can be an arbitrary string, utilized outside of Keygen for verification purposes. For example, Keygen's CLI uses SHA-512 checksums.

  • linkdata.attributes.metadata

    object<string, scalar>, optional

    Object containing release metadata. This can be used to store things such as hash checksums, e.g. sha-256 and sha-512, for integrity verification after download, or for release notes.

linkReturns

A 200 OK response will be returned along with the updated license object.

Upon error, an errors object will be returned along with an HTTP status code indicating the type of error. When an error occurs, the data property will not be included.

Definition

https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/{RELEASE}

Example request

const fetch = require("node-fetch")
 
const response = await fetch("https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/30c64dcd-a74d-4f0d-8479-8745172a4817", {
method: "PATCH",
headers: {
"Authorization": "Bearer {TOKEN}",
"Content-Type": "application/vnd.api+json",
"Accept": "application/vnd.api+json"
},
body: JSON.stringify({
"data": {
"type": "releases",
"attributes": {
"name": "Product v2"
}
}
})
})
 
const { data, errors } = await response.json()
import requests
import json
 
res = requests.patch(
"https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/30c64dcd-a74d-4f0d-8479-8745172a4817",
headers={
"Authorization": "Bearer {TOKEN}",
"Content-Type": "application/vnd.api+json",
"Accept": "application/vnd.api+json"
},
data=json.dumps({
"data": {
"type": "releases",
"attributes": {
"name": "Product v2"
}
}
})
).json()
import SwiftyJSON
import Alamofire
 
Alamofire.request("https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/30c64dcd-a74d-4f0d-8479-8745172a4817",
method: .patch,
headers: [
"Authorization": "Bearer {TOKEN}",
"Content-Type": "application/vnd.api+json",
"Accept": "application/vnd.api+json"
],
parameters: [
"data": [
"type": "releases",
"attributes": [
"name": "Product v2"
]
]
],
encoding: JSONEncoding.default
).responseJSON { response in
let json = JSON(data: response.data!)
}
using RestSharp;
 
var client = new RestClient("https://api.keygen.sh/v1/accounts/{ACCOUNT}");
var request = new RestRequest(
"releases/30c64dcd-a74d-4f0d-8479-8745172a4817",
Method.PATCH
);
 
request.AddHeader("Authorization", "Bearer {TOKEN}");
request.AddHeader("Content-Type", "application/vnd.api+json");
request.AddHeader("Accept", "application/vnd.api+json");
 
request.AddJsonBody(new {
data = new {
type = "releases",
attributes = new {
name = "Product v2"
}
}
});
 
var response = client.Execute(request);
import com.mashape.unirest.http.exceptions.*
import com.mashape.unirest.http.*
import org.json.*
 
val body = JSONObject(mapOf(
"data" to mapOf(
"type" to "releases",
"attributes" to mapOf(
"name" to "Product v2"
)
)
))
 
val res = Unirest.patch("https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/30c64dcd-a74d-4f0d-8479-8745172a4817")
.header("Authorization", "Bearer {TOKEN}")
.header("Content-Type", "application/vnd.api+json")
.header("Accept", "application/vnd.api+json")
.body(body)
.asJson()
import com.mashape.unirest.http.exceptions.*;
import com.mashape.unirest.http.*;
import org.json.*;
 
import static java.util.Map.ofEntries;
import static java.util.Map.entry;
 
JSONObject body = new JSONObject(ofEntries(
entry("data", ofEntries(
entry("type", "releases"),
entry("attributes", ofEntries(
entry("name", "Product v2")
))
))
));
 
HttpResponse<JsonNode> res = Unirest.patch("https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/30c64dcd-a74d-4f0d-8479-8745172a4817")
.header("Authorization", "Bearer {TOKEN}")
.header("Content-Type", "application/vnd.api+json")
.header("Accept", "application/vnd.api+json")
.body(body)
.asJson();
#include <iostream>
#include <string>
#include <cpprest/http_client.h>
#include <cpprest/filestream.h>
 
using namespace std;
using namespace web;
using namespace web::http;
using namespace web::http::client;
using namespace web::json;
using namespace utility;
 
http_client client("https://api.keygen.sh/v1/accounts/{ACCOUNT}");
http_request req;
 
value attrs;
attrs["name"] = value::string("Product v2");
 
value data;
data["type"] = value::string("releases");
data["attributes"] = attrs;
 
value body;
body["data"] = data;
 
req.headers().add("Authorization", "Bearer {TOKEN}");
req.headers().add("Content-Type", "application/vnd.api+json");
req.headers().add("Accept", "application/json");
 
req.set_request_uri("/releases/30c64dcd-a74d-4f0d-8479-8745172a4817");
req.set_method(methods::PATCH);
req.set_body(body.serialize());
 
client.request(req)
.then([](http_response res)
{
auto data = res.extract_json().get();
})
.wait();
curl -X PATCH https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/30c64dcd-a74d-4f0d-8479-8745172a4817 \
-H 'Authorization: Bearer {TOKEN}' \
-H 'Content-Type: application/vnd.api+json' \
-H 'Accept: application/vnd.api+json' \
-d '{
"data": {
"type": "releases",
"attributes": {
"name": "Product v2"
}
}
}'

Example response / 200 OK

{
"data": {
"id": "30c64dcd-a74d-4f0d-8479-8745172a4817",
"type": "releases",
"attributes": {
"name": "Product v2",
"description": null,
"signature": "qqcVWX402un4PEoa+E1VMBfPaBJ1RSxwiGVwrFpGfbI7dulfIqUlovvm1X96m3G2Sjl8gXUDEr8gLEAbJuQQCQ",
"checksum": "lQ8T/qtGvsbqsDaXBqBMh6h2AGL8mTGI4XgLvLDYZA3EumRH8gIMjJ2l5lsO5L0LIvYVqWNXPVzTEp03H4yfZA",
"filename": "Product-2.0.0.dmg",
"filetype": "dmg",
"filesize": 209715200,
"platform": "darwin",
"channel": "stable",
"status": "PUBLISHED",
"downloads": 9000,
"upgrades": 42,
"version": "2.0.0",
"semver": {
"major": 2,
"minor": 0,
"patch": 0,
"prerelease": null,
"build": null
},
"metadata": {
"sha512": "36022a3f0b4bb6f3cdf57276867a210dc81f5c5b2215abf8a93c81ad18fa6bf0b1e36ee24ab7517c9474a1ad445a403d4612899687cabf591f938004df105011"
},
"created": "2017-01-02T20:26:53.464Z",
"updated": "2017-01-02T20:26:53.464Z",
"yanked": null
},
"relationships": {
"account": {
"links": {
"related": "/v1/accounts/{ACCOUNT}"
},
"data": {
"type": "accounts",
"id": "{ACCOUNT}"
}
},
"product": {
"links": {
"related": "/v1/accounts/{ACCOUNT}/releases/30c64dcd-a74d-4f0d-8479-8745172a4817/product"
},
"data": {
"type": "products",
"id": "652da162-cd35-4814-bd28-910a0df0dfad"
}
},
"constraints": {
"links": {
"related": "/v1/accounts/{ACCOUNT}/releases/30c64dcd-a74d-4f0d-8479-8745172a4817/constraints"
}
},
"artifact": {
"links": {
"related": "/v1/accounts/{ACCOUNT}/releases/30c64dcd-a74d-4f0d-8479-8745172a4817/artifact"
}
}
},
"links": {
"self": "/v1/accounts/{ACCOUNT}/releases/30c64dcd-a74d-4f0d-8479-8745172a4817"
}
}
}

linkDelete a release

Permanently deletes a release. It cannot be undone. As an alternative, please see the yank artifact endpoint, which will retain the release resource but it will no longer be able to be downloaded.

linkAuthentication

  • linkBearer

    required

    An authentication token with privileges to manage the resource: either an admin, the product it belongs to.

linkURL Parameters

  • link:account

    string, required

    The identifier (UUID) or slug of your Keygen account.

  • link:release

    string, required

    The identifier (UUID) of the release to be deleted.

linkReturns

A 204 No Content response will be returned.

Upon error, an errors object will be returned along with an HTTP status code indicating the type of error. When an error occurs, the data property will not be included.

Definition

https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/{RELEASE}

Example request

const fetch = require("node-fetch")
 
const response = await fetch("https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/30c64dcd-a74d-4f0d-8479-8745172a4817", {
method: "DELETE",
headers: {
"Authorization": "Bearer {TOKEN}",
"Accept": "application/vnd.api+json"
}
})
import requests
 
res = requests.delete(
"https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/30c64dcd-a74d-4f0d-8479-8745172a4817",
headers={
"Authorization": "Bearer {TOKEN}",
"Accept": "application/vnd.api+json"
}
)
import SwiftyJSON
import Alamofire
 
Alamofire.request("https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/30c64dcd-a74d-4f0d-8479-8745172a4817",
method: .delete,
headers: [
"Authorization": "Bearer {TOKEN}",
"Accept": "application/vnd.api+json"
]
).responseJSON { response in
let status = response.response?.statusCode
}
using RestSharp;
 
var client = new RestClient("https://api.keygen.sh/v1/accounts/{ACCOUNT}");
var request = new RestRequest(
"releases/30c64dcd-a74d-4f0d-8479-8745172a4817",
Method.DELETE
);
 
request.AddHeader("Authorization", "Bearer {TOKEN}");
request.AddHeader("Accept", "application/vnd.api+json");
 
var response = client.Execute(request);
import com.mashape.unirest.http.exceptions.*
import com.mashape.unirest.http.*
 
val res = Unirest.delete("https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/30c64dcd-a74d-4f0d-8479-8745172a4817")
.header("Authorization", "Bearer {TOKEN}")
.header("Accept", "application/vnd.api+json")
.asJson()
import com.mashape.unirest.http.exceptions.*;
import com.mashape.unirest.http.*;
 
HttpResponse<JsonNode> res = Unirest.delete("https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/30c64dcd-a74d-4f0d-8479-8745172a4817")
.header("Authorization", "Bearer {TOKEN}")
.header("Accept", "application/vnd.api+json")
.asJson();
#include <iostream>
#include <string>
#include <cpprest/http_client.h>
#include <cpprest/filestream.h>
 
using namespace std;
using namespace web;
using namespace web::http;
using namespace web::http::client;
using namespace utility;
 
http_client client("https://api.keygen.sh/v1/accounts/{ACCOUNT}");
http_request req;
 
req.headers().add("Authorization", "Bearer {TOKEN}");
req.headers().add("Accept", "application/json");
 
req.set_request_uri("/releases/30c64dcd-a74d-4f0d-8479-8745172a4817");
req.set_method(methods::DELETE);
 
client.request(req)
.then([](http_response res) {
auto status = res.status_code();
})
.wait();
curl -X DELETE https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/30c64dcd-a74d-4f0d-8479-8745172a4817 \
-H 'Authorization: Bearer {TOKEN}' \
-H 'Accept: application/vnd.api+json'

Example response / 204 No Content

No content

linkList all releases

Returns a list of releases. The releases are returned sorted by creation date, with the most recent releases appearing first. Resources are automatically scoped to the authenticated bearer e.g. when authenticated as a user, only releases of that specific user will be listed.

linkAuthentication

  • linkBearer

    optional

    An authentication token with privileges to read the releases: either an admin, the product the releases belong to, an entitled license (via an activation token), or a user with an entitled license. If the product's distribution strategy is OPEN, no authentication is required.

linkURL Parameters

  • link:account

    string, required

    The identifier (UUID) or slug of your Keygen account.

linkFilters

  • linklimit

    integer, default is10

    A limit on the number of releases to be returned. Limit must be a number between 1 and 100.

    https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases?limit=25
  • linkpage

    object<string, integer>

    Object containing page size and page number. Page size must be a number between 1 and 100

    https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases?page[size]=15&page[number]=2
  • linkyanked

    boolean

    The yanked status of the release to filter by.

    https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases?yanked=true
  • linkproduct

    string

    The identifier (UUID) of the product to filter by.

    https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases?product=3ab38aae-bbf7-4846-9c32-af9d94bf5ad4
  • linkplatform

    string

    The identifier (UUID) or name of the platform to filter by.

    https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases?platform=windows
  • linkchannel

    string

    The identifier (UUID) or name of the channel to filter by.

    https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases?channel=stable
  • linkfiletype

    string

    The filetype to filter by.

    https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases?filetype=zip
  • linkversion

    string

    The version to filter by.

    https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases?version=1.0.0
  • linkstatus

    string

    The status of the release to filter by. One of: PUBLISHED, NOT_PUBLISHED, or YANKED.

    https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases?status=PUBLISHED

linkReturns

A 200 OK response will be returned along with a list of release objects.

Upon error, an errors object will be returned along with an HTTP status code indicating the type of error. When an error occurs, the data property will not be included.

Definition

https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases{FILTERS}

Example request

const fetch = require("node-fetch")
 
const response = await fetch("https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases?limit=15", {
method: "GET",
headers: {
"Accept": "application/vnd.api+json",
"Authorization": "Bearer {TOKEN}"
}
})
 
const { data, errors } = await response.json()
import requests
import json
 
res = requests.get(
"https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases?limit=15",
headers={
"Accept": "application/vnd.api+json",
"Authorization": "Bearer {TOKEN}"
}
).json()
import SwiftyJSON
import Alamofire
 
Alamofire.request("https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases?limit=15",
headers: [
"Accept": "application/vnd.api+json",
"Authorization": "Bearer {TOKEN}"
]
).responseJSON { response in
let json = JSON(data: response.data!)
}
using RestSharp;
 
var client = new RestClient("https://api.keygen.sh/v1/accounts/{ACCOUNT}");
var request = new RestRequest("releases", Method.GET);
 
request.AddHeader("Accept", "application/vnd.api+json");
request.AddHeader("Authorization", "Bearer {TOKEN}");
 
request.AddParameter("limit", 15);
 
var response = client.Execute(request);
import com.mashape.unirest.http.exceptions.*
import com.mashape.unirest.http.*
 
val res = Unirest.get("https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases")
.header("Authorization", "Bearer {TOKEN}")
.header("Accept", "application/vnd.api+json")
.queryString("limit", 15)
.asJson()
import com.mashape.unirest.http.exceptions.*;
import com.mashape.unirest.http.*;
 
HttpResponse<JsonNode> res = Unirest.get("https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases")
.header("Authorization", "Bearer {TOKEN}")
.header("Accept", "application/vnd.api+json")
.queryString("limit", 15)
.asJson();
#include <iostream>
#include <string>
#include <cpprest/http_client.h>
#include <cpprest/filestream.h>
 
using namespace std;
using namespace web;
using namespace web::http;
using namespace web::http::client;
using namespace utility;
 
http_client client("https://api.keygen.sh/v1/accounts/{ACCOUNT}");
http_request req;
 
req.headers().add("Authorization", "Bearer {TOKEN}");
req.headers().add("Accept", "application/json");
 
uri_builder uri("/releases");
uri.append_query("limit", 15);
 
req.set_request_uri(uri.to_uri());
req.set_method(methods::GET);
 
client.request(req)
.then([](http_response res) {
auto data = res.extract_json().get();
})
.wait();
curl https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases?limit=15 -g \
-H 'Accept: application/vnd.api+json' \
-H 'Authorization: Bearer {TOKEN}'

Example response / 200 OK

{
"data": [
{
"id": "30c64dcd-a74d-4f0d-8479-8745172a4817",
"type": "releases",
"attributes": {
"name": "Product v1.0.0",
"description": null,
"signature": "qqcVWX402un4PEoa+E1VMBfPaBJ1RSxwiGVwrFpGfbI7dulfIqUlovvm1X96m3G2Sjl8gXUDEr8gLEAbJuQQCQ",
"checksum": "lQ8T/qtGvsbqsDaXBqBMh6h2AGL8mTGI4XgLvLDYZA3EumRH8gIMjJ2l5lsO5L0LIvYVqWNXPVzTEp03H4yfZA",
"filename": "Product-Windows-1.0.0-build.1626813051.zip",
"filetype": "zip",
"filesize": 209715200,
"platform": "windows",
"channel": "stable",
"status": "PUBLISHED",
"downloads": 9000,
"upgrades": 42,
"version": "1.0.0+build.1626813051",
"semver": {
"major": 1,
"minor": 0,
"patch": 0,
"prerelease": null,
"build": "build.1626813051"
},
"metadata": {
"sha512": "36022a3f0b4bb6f3cdf57276867a210dc81f5c5b2215abf8a93c81ad18fa6bf0b1e36ee24ab7517c9474a1ad445a403d4612899687cabf591f938004df105011"
},
"created": "2021-05-14T19:54:16.289Z",
"updated": "2021-05-19T13:30:56.698Z",
"yanked": null
},
"relationships": {
"account": {
"links": {
"related": "/v1/accounts/{ACCOUNT}"
},
"data": {
"type": "accounts",
"id": "{ACCOUNT}"
}
},
"product": {
"links": {
"related": "/v1/accounts/{ACCOUNT}/releases/30c64dcd-a74d-4f0d-8479-8745172a4817/product"
},
"data": {
"type": "products",
"id": "652da162-cd35-4814-bd28-910a0df0dfad"
}
},
"constraints": {
"links": {
"related": "/v1/accounts/{ACCOUNT}/releases/30c64dcd-a74d-4f0d-8479-8745172a4817/constraints"
}
},
"artifact": {
"links": {
"related": "/v1/accounts/{ACCOUNT}/releases/30c64dcd-a74d-4f0d-8479-8745172a4817/artifact"
}
}
},
"links": {
"self": "/v1/accounts/{ACCOUNT}/releases/30c64dcd-a74d-4f0d-8479-8745172a4817"
}
},
]
}

linkRelease actions

Actions for the release resource.

linkCheck for upgrade by version

Check if an upgrade is available for the provided version, product, platform and filetype. This will return the latest release, by semver. Accessing this resource will increment the release's upgrades counter by 1. Releases can be upgraded according to the following rules:

  • Licenses: can access releases for their product, given the release was created prior to the license's expiry (if the license has an expiry), and that the license fulfills all of the release's entitlement contraints. Exact behavior will also depend on the product's distribution strategy, and the policy's expiration strategy.
  • Users: can access releases for their products, given the user has one or more associated licenses which fulfill the license requirements above.
  • Products: can access any release for their product.
  • Admins: can access any release for their account.

For framework-specific integrations, see the auto-updates section.

linkAuthentication

  • linkBearer

    optional

    An authentication token with privileges to upgrade: either an admin, the product it belongs to, an entitled license (via an activation token), or a user with an entitled license. If the product's distribution strategy is OPEN, no authentication is required.

linkURL Parameters

  • link:account

    string, required

    The identifier (UUID) or slug of your Keygen account.

linkQuery Parameters

  • linkversion

    semver, required

    The current running version of the release. We will use this to determine if a newer version is available.

  • linkproduct

    string, required

    The product identifier (UUID) the upgrade request is for.

  • linkplatform

    string, required

    The platform for the upgrade.

  • linkfiletype

    string, required

    The filetype for the upgrade.

  • linkchannel

    string, optional, default isstable

    The release channel. One of: stable, rc, beta, alpha or dev. The rc channel will include stable releases. The beta channel will include rc and stable. Alpha will include beta, rc, and stable. Dev will only include releases on the dev channel (you can think of it as 'nightly' or 'edge', i.e. following a master branch).

  • linkconstraint

    semver, optional

    The version constraint for the upgrade. For example, constraint=1.0 will constrain all upgrades to version 1.x, while constraint=1.0.0 will constrain to version 1.0.x. This is useful if a given license is only entitled to a specific version range.

linkReturns

If an update is available, a 303 See Other status will be returned redirecting to the upgrade release artifact. Otherwise, 204 No Content will be returned.

Please note: If you receive a 400 error from AWS S3, you may need to configure your HTTP client to not automatically follow redirects. Some HTTP clients will insecurely replay the entire request, including your Keygen Authorization header, to the cross-origin AWS S3 resource, resulting in a 400 response from S3. You can manually follow the redirect by issuing a GET request to the Location header, without the superfluous headers.

Alternatively, you can pass in your API token via the request's query parameters, e.g. ?token=activ-XXX, instead of the Authorization header.

Upon error, an errors object will be returned along with an HTTP status code indicating the type of error. When an error occurs, the data property will not be included.

Definition

https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/actions/upgrade

Example request

const fetch = require("node-fetch")
 
const response = await fetch("https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/actions/upgrade?version=1.0.0&constraint=1.0&platform=macos&filetype=dmg&product={ACCOUNT}", {
redirect: "manual",
method: "GET",
headers: {
"Authorization": "Bearer {TOKEN}"
"Accept": "application/vnd.api+json"
}
})
 
const { meta, data, errors } = await response.json()
import requests
import json
 
res = requests.get(
"https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/actions/upgrade?version=1.0.0&constraint=1.0&channel=stable&platform=macos&filetype=dmg&product={ACCOUNT}",
headers={
"Authorization": "Bearer {TOKEN}",
"Accept": "application/vnd.api+json"
}
).json()
import SwiftyJSON
import Alamofire
 
Alamofire.request("https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/actions/upgrade?version=1.0.0&constraint=1.0&channel=stable&platform=macos&filetype=dmg&product={ACCOUNT}",
headers: [
"Authorization": "Bearer {TOKEN}",
"Accept": "application/vnd.api+json"
]
).responseJSON { response in
let json = JSON(data: response.data!)
}
using RestSharp;
 
var client = new RestClient("https://api.keygen.sh/v1/accounts/{ACCOUNT}");
var request = new RestRequest(
"releases/actions/upgrade",
Method.GET
);
 
request.AddHeader("Authorization", "Bearer {TOKEN}");
request.AddHeader("Accept", "application/vnd.api+json");
 
request.AddParameter("product", "{ACCOUNT}");
request.AddParameter("version", "1.0.0");
request.AddParameter("constraint", "1.0");
request.AddParameter("channel", "stable");
request.AddParameter("platform", "macos");
request.AddParameter("filetype", "dmg");
 
var response = client.Execute(request);
import com.mashape.unirest.http.exceptions.*
import com.mashape.unirest.http.*
 
val res = Unirest.get("https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/actions/upgrade")
.header("Authorization", "Bearer {TOKEN}")
.header("Accept", "application/vnd.api+json")
.queryString("product", "{ACCOUNT}")
.queryString("version", "1.0.0")
.queryString("constraint", "1.0")
.queryString("channel", "stable")
.queryString("platform", "macos")
.queryString("filetype", "dmg")
.asJson()
import com.mashape.unirest.http.exceptions.*;
import com.mashape.unirest.http.*;
 
HttpResponse<JsonNode> res = Unirest.get("https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/actions/upgrade")
.header("Authorization", "Bearer {TOKEN}")
.header("Accept", "application/vnd.api+json")
.queryString("product", "{ACCOUNT}")
.queryString("version", "1.0.0")
.queryString("constraint", "1.0")
.queryString("channel", "stable")
.queryString("platform", "macos")
.queryString("filetype", "dmg")
.asJson();
#include <iostream>
#include <string>
#include <cpprest/http_client.h>
#include <cpprest/filestream.h>
 
using namespace std;
using namespace web;
using namespace web::http;
using namespace web::http::client;
using namespace utility;
 
http_client client("https://api.keygen.sh/v1/accounts/{ACCOUNT}");
http_request req;
 
req.headers().add("Authorization", "Bearer {TOKEN}");
req.headers().add("Accept", "application/json");
 
uri_builder uri("/releases/actions/upgrade");
uri.append_query("product", "{ACCOUNT}");
uri.append_query("version", "1.0.0");
uri.append_query("constraint", "1.0");
uri.append_query("channel", "stable");
uri.append_query("platform", "macos");
uri.append_query("filetype", "dmg");
 
req.set_request_uri(uri.to_uri());
req.set_method(methods::GET);
 
client.request(req)
.then([](http_response res) {
auto status = res.status_code();
})
.wait();
curl -G -X GET https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/actions/upgrade \
-H 'Authorization: Bearer {TOKEN}' \
-H 'Accept: application/vnd.api+json' \
-d 'product={ACCOUNT}' \
-d 'version=1.0.0' \
-d 'constraint=1.0' \
-d 'channel=stable' \
-d 'platform=macos' \
-d 'filetype=dmg'

Example response / 303 See Other

Location: https://keygen-dist.s3.us-east-2.amazonaws.com/artifacts/{ACCOUNT}/30c64dcd-a74d-4f0d-8479-8745172a4817/prod/Product-1-3-0.dmg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIMMTBUOYHFTLV23Q%2F20210720%2Fus-east-2%2Fs3%2Faws4_request&X-Amz-Date=20210720T145510Z&X-Amz-Expires=60&X-Amz-SignedHeaders=host&X-Amz-Signature=8b9d214c0db8116a0c96d93140dda5367183e36ee367d00c82267a40546d3927
{
"data": {
"id": "ddc77e3f-808d-4344-9926-e885f4a8aa3c",
"type": "artifacts",
"attributes": {
"key": "prod/Product-1-3-0.dmg",
"created": "2021-07-26T14:38:43.571Z",
"updated": "2021-07-26T14:40:26.424Z"
},
"relationships": {
"account": {
"links": {
"related": "/v1/accounts/{ACCOUNT}"
},
"data": {
"type": "accounts",
"id": "{ACCOUNT}"
}
},
"product": {
"links": {
"related": "/v1/accounts/{ACCOUNT}/products/652da162-cd35-4814-bd28-910a0df0dfad"
},
"data": {
"type": "products",
"id": "652da162-cd35-4814-bd28-910a0df0dfad"
}
},
"release": {
"links": {
"related": "/v1/accounts/{ACCOUNT}/releases/30c64dcd-a74d-4f0d-8479-8745172a4817"
},
"data": {
"type": "releases",
"id": "30c64dcd-a74d-4f0d-8479-8745172a4817"
}
}
},
"links": {
"related": "/v1/accounts/{ACCOUNT}/releases/30c64dcd-a74d-4f0d-8479-8745172a4817/artifact",
"self": "/v1/accounts/{ACCOUNT}/artifacts/ddc77e3f-808d-4344-9926-e885f4a8aa3c"
}
},
"meta": {
"current": "1.0.0",
"next": "1.3.0"
}
}

linkCheck for upgrade by ID

Check if an upgrade is available for the release. This will return the latest release, by semver. Accessing this resource will increment the release's upgrades counter by 1. Releases can be upgraded according to the following rules:

  • Licenses: can access releases for their product, given the release was created prior to the license's expiry (if the license has an expiry), and that the license fulfills all of the release's entitlement contraints. Exact behavior will also depend on the product's distribution strategy, and the policy's expiration strategy.
  • Users: can access releases for their products, given the user has one or more associated licenses which fulfill the license requirements above.
  • Products: can access any release for their product.
  • Admins: can access any release for their account.

For framework-specific integrations, see the auto-updates section.

linkAuthentication

  • linkBearer

    optional

    An authentication token with privileges to upgrade: either an admin, the product it belongs to, an entitled license (via an activation token), or a user with an entitled license. If the product's distribution strategy is OPEN, no authentication is required.

linkURL Parameters

  • link:account

    string, required

    The identifier (UUID) or slug of your Keygen account.

  • link:release

    string, required

    The identifier (UUID) of the current release.

linkQuery Parameters

  • linkchannel

    string, optional, default isstable

    The release channel. One of: stable, rc, beta, alpha or dev. The rc channel will include stable releases. The beta channel will include rc and stable. Alpha will include beta, rc, stable. Dev will only include releases on the dev channel.

  • linkconstraint

    semver, optional

    The version constraint for the upgrade. For example, constraint=1.0 will constrain all upgrades to version 1.x, while constraint=1.0.0 will constrain to version 1.0.x. This is useful if a given license is only entitled to a specific version range.

linkReturns

If an update is available, a 303 See Other status will be returned redirecting to the upgrade release artifact. Otherwise, 204 No Content will be returned.

Please note: If you receive a 400 error from AWS S3, you may need to configure your HTTP client to not automatically follow redirects. Some HTTP clients will insecurely replay the entire request, including your Keygen Authorization header, to the cross-origin AWS S3 resource, resulting in a 400 response from S3. You can manually follow the redirect by issuing a GET request to the Location header, without the superfluous headers.

Alternatively, you can pass in your API token via the request's query parameters, e.g. ?token=activ-XXX, instead of the Authorization header.

Upon error, an errors object will be returned along with an HTTP status code indicating the type of error. When an error occurs, the data property will not be included.

Definition

https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/{RELEASE}/actions/upgrade

Example request

const fetch = require("node-fetch")
 
const response = await fetch("https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/{RELEASE}/actions/upgrade?constraint=1.0.0&channel=stable", {
redirect: "manual",
method: "GET",
headers: {
"Authorization": "Bearer {TOKEN}",
"Accept": "application/vnd.api+json"
}
})
 
const { meta, data, errors } = await response.json()
import requests
import json
 
res = requests.get(
"https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/{RELEASE}/actions/upgrade?constraint=1.0.0&channel=stable",
headers={
"Authorization": "Bearer {TOKEN}",
"Accept": "application/vnd.api+json"
}
).json()
import SwiftyJSON
import Alamofire
 
Alamofire.request("https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/{RELEASE}/actions/upgrade?constraint=1.0.0&channel=stable",
headers: [
"Authorization": "Bearer {TOKEN}",
"Accept": "application/vnd.api+json"
]
).responseJSON { response in
let json = JSON(data: response.data!)
}
using RestSharp;
 
var client = new RestClient("https://api.keygen.sh/v1/accounts/{ACCOUNT}");
var request = new RestRequest(
"releases/{RELEASE}/actions/upgrade",
Method.GET
);
 
request.AddHeader("Authorization", "Bearer {TOKEN}");
request.AddHeader("Accept", "application/vnd.api+json");
 
request.AddParameter("constraint", "1.0.0");
request.AddParameter("channel", "stable");
 
var response = client.Execute(request);
import com.mashape.unirest.http.exceptions.*
import com.mashape.unirest.http.*
 
val res = Unirest.get("https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/{RELEASE}/actions/upgrade")
.header("Authorization", "Bearer {TOKEN}")
.header("Accept", "application/vnd.api+json")
.queryString("constraint", "1.0.0")
.queryString("channel", "stable")
.asJson()
import com.mashape.unirest.http.exceptions.*;
import com.mashape.unirest.http.*;
 
HttpResponse<JsonNode> res = Unirest.get("https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/{RELEASE}/actions/upgrade")
.header("Authorization", "Bearer {TOKEN}")
.header("Accept", "application/vnd.api+json")
.queryString("constraint", "1.0.0")
.queryString("channel", "stable")
.asJson();
#include <iostream>
#include <string>
#include <cpprest/http_client.h>
#include <cpprest/filestream.h>
 
using namespace std;
using namespace web;
using namespace web::http;
using namespace web::http::client;
using namespace utility;
 
http_client client("https://api.keygen.sh/v1/accounts/{ACCOUNT}");
http_request req;
 
req.headers().add("Authorization", "Bearer {TOKEN}");
req.headers().add("Accept", "application/json");
 
uri_builder uri("/releases/{RELEASE}/actions/upgrade");
uri.append_query("constraint", "1.0.0");
uri.append_query("channel", "stable");
 
req.set_request_uri(uri.to_uri());
req.set_method(methods::GET);
 
client.request(req)
.then([](http_response res) {
auto status = res.status_code();
})
.wait();
curl -G -X GET https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/{RELEASE}/actions/upgrade \
-H 'Authorization: Bearer {TOKEN}' \
-H 'Accept: application/vnd.api+json' \
-d 'constraint=1.0.0' \
-d 'channel=stable'

Example response / 303 See Other

Location: https://keygen-dist.s3.us-east-2.amazonaws.com/artifacts/{ACCOUNT}/30c64dcd-a74d-4f0d-8479-8745172a4817/Product-1-0-1.dmg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIMMTBUOYHFTLV23Q%2F20210720%2Fus-east-2%2Fs3%2Faws4_request&X-Amz-Date=20210720T145510Z&X-Amz-Expires=60&X-Amz-SignedHeaders=host&X-Amz-Signature=8b9d214c0db8116a0c96d93140dda5367183e36ee367d00c82267a40546d3927
{
"data": {
"id": "ddc77e3f-808d-4344-9926-e885f4a8aa3c",
"type": "artifacts",
"attributes": {
"key": "Product-1-0-1.dmg",
"created": "2021-07-26T14:38:43.571Z",
"updated": "2021-07-26T14:40:26.424Z"
},
"relationships": {
"account": {
"links": {
"related": "/v1/accounts/{ACCOUNT}"
},
"data": {
"type": "accounts",
"id": "{ACCOUNT}"
}
},
"product": {
"links": {
"related": "/v1/accounts/{ACCOUNT}/products/652da162-cd35-4814-bd28-910a0df0dfad"
},
"data": {
"type": "products",
"id": "652da162-cd35-4814-bd28-910a0df0dfad"
}
},
"release": {
"links": {
"related": "/v1/accounts/{ACCOUNT}/releases/30c64dcd-a74d-4f0d-8479-8745172a4817"
},
"data": {
"type": "releases",
"id": "30c64dcd-a74d-4f0d-8479-8745172a4817"
}
}
},
"links": {
"related": "/v1/accounts/{ACCOUNT}/releases/30c64dcd-a74d-4f0d-8479-8745172a4817/artifact",
"self": "/v1/accounts/{ACCOUNT}/artifacts/ddc77e3f-808d-4344-9926-e885f4a8aa3c"
}
},
"meta": {
"current": "1.0.0",
"next": "1.0.1"
}
}

linkRelease relationships

Relationship endpoints for the release resource.

linkAttach entitlement constraints

Attach entitlement constraints to a release. This will immediately be taken into effect for all future download and upgrade requests. Licenses and users must possess all entitlement constraints to be able to download or upgrade the release.

linkAuthentication

  • linkBearer

    required

    An authentication token with privileges to manage the release: either an admin, or the product it belongs to.

linkURL Parameters

  • link:account

    string, required

    The identifier (UUID) or slug of your Keygen account.

  • link:release

    string, required

    The identifier (UUID) of the release to be modified.

linkRelationships

linkReturns

A 201 Created response will be returned along with an array of constraint objects.

Upon error, an errors object will be returned along with an HTTP status code indicating the type of error. When an error occurs, the data property will not be included.

Definition

https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/{RELEASE}/constraints

Example request

const fetch = require("node-fetch")
 
const response = await fetch("https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/b18e3f3a-330c-4d8d-ae2e-014db21fa827/constraints", {
method: "POST",
headers: {
"Authorization": "Bearer {TOKEN}",
"Content-Type": "application/vnd.api+json",
"Accept": "application/vnd.api+json"
},
body: JSON.stringify({
"data": [
{
"type": "constraints",
"relationships": {
"entitlement": {
"data": { "type": "entitlements", "id": "57f1ceb4-6bf4-44dd-8967-de88364bf9eb" }
}
}
}
]
})
})
 
const { data, errors } = await response.json()
import requests
import json
 
res = requests.post(
"https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/b18e3f3a-330c-4d8d-ae2e-014db21fa827/constraints",
headers={
"Authorization": "Bearer {TOKEN}",
"Content-Type": "application/vnd.api+json",
"Accept": "application/vnd.api+json"
},
data=json.dumps({
"data": [
{
"type": "constraints",
"relationships": {
"entitlement": {
"data": { "type": "entitlements", "id": "57f1ceb4-6bf4-44dd-8967-de88364bf9eb" }
}
}
}
]
})
).json()
import SwiftyJSON
import Alamofire
 
Alamofire.request("https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/b18e3f3a-330c-4d8d-ae2e-014db21fa827/constraints",
method: .post,
headers: [
"Authorization": "Bearer {TOKEN}",
"Content-Type": "application/vnd.api+json",
"Accept": "application/vnd.api+json"
],
parameters: [
"data": [
[
"type": "constraints",
"relationships": [
"entitlement": [
"data": ["type": "entitlements", "id": "57f1ceb4-6bf4-44dd-8967-de88364bf9eb"]
]
]
]
]
],
encoding: JSONEncoding.default
).responseJSON { response in
let json = JSON(data: response.data!)
}
using RestSharp;
 
var client = new RestClient("https://api.keygen.sh/v1/accounts/{ACCOUNT}");
var request = new RestRequest(
"releases/b18e3f3a-330c-4d8d-ae2e-014db21fa827/constraints",
Method.POST
);
 
request.AddHeader("Authorization", "Bearer {TOKEN}");
request.AddHeader("Content-Type", "application/vnd.api+json");
request.AddHeader("Accept", "application/vnd.api+json");
 
request.AddJsonBody(new {
data = [
new {
type = "constraints",
relationships = new {
entitlement = new {
data = new { type = "entitlements", id = "57f1ceb4-6bf4-44dd-8967-de88364bf9eb" }
}
}
}
});
 
var response = client.Execute(request);
import com.mashape.unirest.http.exceptions.*
import com.mashape.unirest.http.*
import org.json.*
 
val body = JSONObject(mapOf(
"data" to listOf(
mapOf(
"type" to "constraints",
"relationships" to mapOf(
"entitlement" to mapOf(
"data" to mapOf("type" to "entitlements", "id" to "57f1ceb4-6bf4-44dd-8967-de88364bf9eb")
)
)
)
)
))
 
val res = Unirest.post("https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/b18e3f3a-330c-4d8d-ae2e-014db21fa827/constraints")
.header("Authorization", "Bearer {TOKEN}")
.header("Content-Type", "application/vnd.api+json")
.header("Accept", "application/vnd.api+json")
.body(body)
.asJson()
import com.mashape.unirest.http.exceptions.*;
import com.mashape.unirest.http.*;
import org.json.*;
 
import static java.util.Map.ofEntries;
import static java.util.Map.entry;
import static java.util.List.of;
 
JSONObject body = new JSONObject(ofEntries(
entry("data", of(
ofEntries(
entry("type", "constraints"),
entry("relationships", ofEntries(
entry("entitlement", ofEntries(
entry("data", ofEntries(
entry("type", "entitlements"),
entry("id", "57f1ceb4-6bf4-44dd-8967-de88364bf9eb")
))
))
))
)
))
));
 
HttpResponse<JsonNode> res = Unirest.post("https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/b18e3f3a-330c-4d8d-ae2e-014db21fa827/constraints")
.header("Authorization", "Bearer {TOKEN}")
.header("Content-Type", "application/vnd.api+json")
.header("Accept", "application/vnd.api+json")
.body(body)
.asJson();
#include <iostream>
#include <string>
#include <cpprest/http_client.h>
#include <cpprest/filestream.h>
 
using namespace std;
using namespace web;
using namespace web::http;
using namespace web::http::client;
using namespace web::json;
using namespace utility;
 
http_client client("https://api.keygen.sh/v1/accounts/{ACCOUNT}");
http_request req;
 
value entl_linkage;
entl_linkage["type"] = value::string("entitlements");
entl_linkage["id"] = value::string("57f1ceb4-6bf4-44dd-8967-de88364bf9eb");
 
value entl;
entl["data"] = entl_linkage;
 
value rels;
rels["entitlement"] = entl;
 
value constraint;
constraint["type"] = value::string("constraints");
constraint["relationships"] = rels;
 
value data = value::array(1);
data[0] = constraint;
 
value body;
body["data"] = data;
 
req.headers().add("Authorization", "Bearer {TOKEN}");
req.headers().add("Content-Type", "application/vnd.api+json");
req.headers().add("Accept", "application/json");
 
req.set_request_uri("/releases/b18e3f3a-330c-4d8d-ae2e-014db21fa827/constraints");
req.set_method(methods::POST);
req.set_body(body.serialize());
 
client.request(req)
.then([](http_response res)
{
auto data = res.extract_json().get();
})
.wait();
curl -X POST https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/b18e3f3a-330c-4d8d-ae2e-014db21fa827/constraints \
-H 'Authorization: Bearer {TOKEN}' \
-H 'Content-Type: application/vnd.api+json' \
-H 'Accept: application/vnd.api+json' \
-d '{
"data": [
{
"type": "constraints",
"relationships": {
"entitlement": {
"data": { "type": "entitlements", "id": "57f1ceb4-6bf4-44dd-8967-de88364bf9eb" }
}
}
}
]
}'

Example response / 201 Created

{
"data": [
{
"id": "14fb3e6a-2b30-42b4-b2ff-06ca2e6c0608",
"type": "constraints",
"attributes": {
"created": "2017-01-02T20:26:53.464Z",
"updated": "2017-01-02T20:26:53.464Z"
},
"relationships": {
"account": {
"links": {
"related": "/v1/accounts/{ACCOUNT}"
},
"data": {
"type": "accounts",
"id": "{ACCOUNT}"
}
},
"entitlement": {
"links": {
"related": "/v1/accounts/{ACCOUNT}/entitlements/57f1ceb4-6bf4-44dd-8967-de88364bf9eb"
},
"data": {
"type": "entitlements",
"id": "57f1ceb4-6bf4-44dd-8967-de88364bf9eb"
}
},
"release": {
"links": {
"related": "/v1/accounts/{ACCOUNT}/releases/b18e3f3a-330c-4d8d-ae2e-014db21fa827"
},
"data": {
"type": "releases",
"id": "b18e3f3a-330c-4d8d-ae2e-014db21fa827"
}
}
},
"links": {
"related": "/v1/accounts/{ACCOUNT}/releases/b18e3f3a-330c-4d8d-ae2e-014db21fa827/constraints/14fb3e6a-2b30-42b4-b2ff-06ca2e6c0608"
}
}
]
}

linkDetach entitlement constraints

Detach entitlement constraints from a release. This will immediately be taken into effect for all future download and upgrade requests.

linkAuthentication

  • linkBearer

    required

    An authentication token with privileges to manage the release: either an admin, or the product it belongs to.

linkURL Parameters

  • link:account

    string, required

    The identifier (UUID) or slug of your Keygen account.

  • link:release

    string, required

    The identifier (UUID) of the release to be modified.

linkReturns

A 204 No Content response will be returned.

Upon error, an errors object will be returned along with an HTTP status code indicating the type of error. When an error occurs, the data property will not be included.

Definition

https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/{RELEASE}/constraints

Example request

const fetch = require("node-fetch")
 
const response = await fetch("https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/b18e3f3a-330c-4d8d-ae2e-014db21fa827/constraints", {
method: "DELETE",
headers: {
"Authorization": "Bearer {TOKEN}",
"Content-Type": "application/vnd.api+json",
"Accept": "application/vnd.api+json"
},
body: JSON.stringify({
"data": [
{
"type": "constraint",
"id": "14fb3e6a-2b30-42b4-b2ff-06ca2e6c0608"
}
]
})
})
 
const { data, errors } = await response.json()
import requests
import json
 
res = requests.delete(
"https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/b18e3f3a-330c-4d8d-ae2e-014db21fa827/constraints",
headers={
"Authorization": "Bearer {TOKEN}",
"Content-Type": "application/vnd.api+json",
"Accept": "application/vnd.api+json"
},
data=json.dumps({
"data": [
{
"type": "constraint",
"id": "14fb3e6a-2b30-42b4-b2ff-06ca2e6c0608"
}
]
})
).json()
import SwiftyJSON
import Alamofire
 
Alamofire.request("https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/b18e3f3a-330c-4d8d-ae2e-014db21fa827/constraints",
method: .delete,
headers: [
"Authorization": "Bearer {TOKEN}",
"Content-Type": "application/vnd.api+json",
"Accept": "application/vnd.api+json"
],
parameters: [
"data": [
[
"type": "constraint",
"id": "14fb3e6a-2b30-42b4-b2ff-06ca2e6c0608"
]
]
],
encoding: JSONEncoding.default
).responseJSON { response in
let json = JSON(data: response.data!)
}
using RestSharp;
 
var client = new RestClient("https://api.keygen.sh/v1/accounts/{ACCOUNT}");
var request = new RestRequest(
"releases/b18e3f3a-330c-4d8d-ae2e-014db21fa827/constraints",
Method.DELETE
);
 
request.AddHeader("Authorization", "Bearer {TOKEN}");
request.AddHeader("Content-Type", "application/vnd.api+json");
request.AddHeader("Accept", "application/vnd.api+json");
 
request.AddJsonBody(new {
data = [
new {
type = "constraint",
id = "14fb3e6a-2b30-42b4-b2ff-06ca2e6c0608"
}
]
});
 
var response = client.Execute(request);
import com.mashape.unirest.http.exceptions.*
import com.mashape.unirest.http.*
import org.json.*
 
val body = JSONObject(mapOf(
"data" to listOf(
mapOf(
"type" to "constraint",
"id" to "14fb3e6a-2b30-42b4-b2ff-06ca2e6c0608"
)
)
))
 
val res = Unirest.delete("https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/b18e3f3a-330c-4d8d-ae2e-014db21fa827/constraints")
.header("Authorization", "Bearer {TOKEN}")
.header("Content-Type", "application/vnd.api+json")
.header("Accept", "application/vnd.api+json")
.body(body)
.asJson()
import com.mashape.unirest.http.exceptions.*;
import com.mashape.unirest.http.*;
import org.json.*;
 
import static java.util.Map.ofEntries;
import static java.util.Map.entry;
import static java.util.List.of;
 
JSONObject body = new JSONObject(ofEntries(
entry("data", of(
ofEntries(
entry("type", "constraint"),
entry("id", "14fb3e6a-2b30-42b4-b2ff-06ca2e6c0608")
)
))
));
 
HttpResponse<JsonNode> res = Unirest.delete("https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/b18e3f3a-330c-4d8d-ae2e-014db21fa827/constraints")
.header("Authorization", "Bearer {TOKEN}")
.header("Content-Type", "application/vnd.api+json")
.header("Accept", "application/vnd.api+json")
.body(body)
.asJson();
#include <iostream>
#include <string>
#include <cpprest/http_client.h>
#include <cpprest/filestream.h>
 
using namespace std;
using namespace web;
using namespace web::http;
using namespace web::http::client;
using namespace web::json;
using namespace utility;
 
http_client client("https://api.keygen.sh/v1/accounts/{ACCOUNT}");
http_request req;
 
value constrant;
constraint["type"] = value::string("constraint");
constraint["id"] = value::string("14fb3e6a-2b30-42b4-b2ff-06ca2e6c0608");
 
value data = value::array(1);
data[0] = constraint;
 
value body;
body["data"] = data;
 
req.headers().add("Authorization", "Bearer {TOKEN}");
req.headers().add("Content-Type", "application/vnd.api+json");
req.headers().add("Accept", "application/json");
 
req.set_request_uri("/releases/b18e3f3a-330c-4d8d-ae2e-014db21fa827/constraints");
req.set_method(methods::DELETE);
req.set_body(body.serialize());
 
client.request(req)
.then([](http_response res)
{
auto data = res.extract_json().get();
})
.wait();
curl -X DELETE https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/b18e3f3a-330c-4d8d-ae2e-014db21fa827/constraints \
-H 'Content-Type: application/vnd.api+json' \
-H 'Accept: application/vnd.api+json' \
-H 'Authorization: Bearer {TOKEN}' \
-d '{
"data": [
{
"type": "constraint",
"id": "14fb3e6a-2b30-42b4-b2ff-06ca2e6c0608"
}
]
}'

Example response / 204 No Content

No Content

linkList entitlement constraints

Returns a list of entitlement constraints attached to the release. The constraints are returned sorted by creation date, with the most recent constraints appearing first.

linkAuthentication

  • linkBearer

    required

    An authentication token with privileges to view the resource: either an admin, or the product it belongs to.

linkURL Parameters

  • link:account

    string, required

    The identifier (UUID) or slug of your Keygen account.

  • link:release

    string, required

    The identifier (UUID)of the release to list constraints for.

linkFilters

  • linklimit

    integer, default is10

    A limit on the number of constraints to be returned. Limit must be a number between 1 and 100.

    https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/b18e3f3a-330c-4d8d-ae2e-014db21fa827/constraints?limit=25
  • linkpage

    object<string, integer>

    Object containing page size and page number. Page size must be a number between 1 and 100

    https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/b18e3f3a-330c-4d8d-ae2e-014db21fa827/constraints?page[size]=15&page[number]=2

linkReturns

A 200 OK response will be returned along with a list of constraint objects.

Upon error, an errors object will be returned along with an HTTP status code indicating the type of error. When an error occurs, the data property will not be included.

Definition

https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/{ID}/constraints{FILTERS}

Example request

const fetch = require("node-fetch")
 
const response = await fetch("https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/b18e3f3a-330c-4d8d-ae2e-014db21fa827/constraints?limit=15", {
method: "GET",
headers: {
"Authorization": "Bearer {TOKEN}",
"Accept": "application/vnd.api+json"
}
})
 
const { data, errors } = await response.json()
import requests
import json
 
res = requests.get(
"https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/b18e3f3a-330c-4d8d-ae2e-014db21fa827/constraints?limit=15",
headers={
"Authorization": "Bearer {TOKEN}",
"Accept": "application/vnd.api+json"
}
).json()
import SwiftyJSON
import Alamofire
 
Alamofire.request("https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/b18e3f3a-330c-4d8d-ae2e-014db21fa827/constraints?limit=15",
headers: [
"Authorization": "Bearer {TOKEN}",
"Accept": "application/vnd.api+json"
]
).responseJSON { response in
let json = JSON(data: response.data!)
}
using RestSharp;
 
var client = new RestClient("https://api.keygen.sh/v1/accounts/{ACCOUNT}");
var request = new RestRequest("entitlements", Method.GET);
 
request.AddHeader("Authorization", "Bearer {TOKEN}");
request.AddHeader("Accept", "application/vnd.api+json");
 
request.AddParameter("list", 15);
 
var response = client.Execute(request);
import com.mashape.unirest.http.exceptions.*
import com.mashape.unirest.http.*
 
val res = Unirest.get("https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/b18e3f3a-330c-4d8d-ae2e-014db21fa827/constraints")
.header("Authorization", "Bearer {TOKEN}")
.header("Accept", "application/vnd.api+json")
.queryString("limit", 15)
.asJson()
import com.mashape.unirest.http.exceptions.*;
import com.mashape.unirest.http.*;
 
HttpResponse<JsonNode> res = Unirest.get("https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/b18e3f3a-330c-4d8d-ae2e-014db21fa827/constraints")
.header("Authorization", "Bearer {TOKEN}")
.header("Accept", "application/vnd.api+json")
.queryString("limit", 15)
.asJson();
#include <iostream>
#include <string>
#include <cpprest/http_client.h>
#include <cpprest/filestream.h>
 
using namespace std;
using namespace web;
using namespace web::http;
using namespace web::http::client;
using namespace utility;
 
http_client client("https://api.keygen.sh/v1/accounts/{ACCOUNT}");
http_request req;
 
req.headers().add("Authorization", "Bearer {TOKEN}");
req.headers().add("Accept", "application/json");
 
uri_builder uri("/releases/b18e3f3a-330c-4d8d-ae2e-014db21fa827/constraints");
uri.append_query("limit", 15);
 
req.set_request_uri(uri.to_uri());
req.set_method(methods::GET);
 
client.request(req)
.then([](http_response res) {
auto data = res.extract_json().get();
})
.wait();
curl https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/b18e3f3a-330c-4d8d-ae2e-014db21fa827/constraints?limit=15 -g \
-H 'Authorization: Bearer {TOKEN}' \
-H 'Accept: application/vnd.api+json'

Example response / 200 OK

{
"data": [
{
"id": "14fb3e6a-2b30-42b4-b2ff-06ca2e6c0608",
"type": "constraints",
"attributes": {
"created": "2017-01-02T20:26:53.464Z",
"updated": "2017-01-02T20:26:53.464Z"
},
"relationships": {
"account": {
"links": {
"related": "/v1/accounts/{ACCOUNT}"
},
"data": {
"type": "accounts",
"id": "{ACCOUNT}"
}
},
"entitlement": {
"links": {
"related": "/v1/accounts/{ACCOUNT}/entitlements/57f1ceb4-6bf4-44dd-8967-de88364bf9eb"
},
"data": {
"type": "entitlements",
"id": "57f1ceb4-6bf4-44dd-8967-de88364bf9eb"
}
},
"release": {
"links": {
"related": "/v1/accounts/{ACCOUNT}/releases/b18e3f3a-330c-4d8d-ae2e-014db21fa827"
},
"data": {
"type": "releases",
"id": "b18e3f3a-330c-4d8d-ae2e-014db21fa827"
}
}
},
"links": {
"related": "/v1/accounts/{ACCOUNT}/releases/b18e3f3a-330c-4d8d-ae2e-014db21fa827/constraints/14fb3e6a-2b30-42b4-b2ff-06ca2e6c0608"
}
}
],
}

linkRelease artifacts

Access and manage the artifacts of the release resource.

linkDownload release artifact

Download the release artifact. This can be used to generate temporary download URLs for licensees. Accessing this resource will increment the release's downloads counter by 1. To download the artifact, follow the redirect Location header.

Releases can be downloaded according to the following rules:

  • Licenses: can access releases for their product, given the release was created prior to the license's expiry (if the license has an expiry), and that the license fulfills all of the release's entitlement contraints. Exact behavior will also depend on the product's distribution strategy, and the policy's expiration strategy.
  • Users: can access releases for their products, given the user has one or more associated licenses which fulfill the license requirements above.
  • Products: can access any release for their product.
  • Admins: can access any release for their account.
Use an admin or product token to generate a download link with a time-to-live longer than 60 seconds. E.g. for use inside of a "welcome" email or on a "success" page. Use short-lived download links for "download" buttons inside of a UI portal.

linkAuthentication

  • linkBearer

    optional

    An authentication token with privileges to download the release: either an admin, the product it belongs to, an entitled license (via an activation token), or a user with an entitled license. If the product's distribution strategy is OPEN, no authentication is required.

linkURL Parameters

  • link:account

    string, required

    The identifier (UUID) or slug of your Keygen account.

  • link:release

    string, required

    The identifier (UUID) of the release to be downloaded.

linkQuery Parameters

  • linkttl

    integer, optional, default is60protectedProtected params are only available for bearers with an admin or product role.

    The time-to-live (TTL), in seconds, for the download link. The value can be between 1 minute and 1 week, in seconds. Only admins and products can set this parameter.

linkReturns

If an artifact is available, a 303 See Other status will be returned redirecting to the download URL for the artifact, hosted on AWS S3. Follow the redirect to download the release.

Please note: If you receive a 400 error from AWS S3, you may need to configure your HTTP client to not automatically follow redirects. Some HTTP clients will insecurely replay the entire request, including your Keygen Authorization header, to the cross-origin AWS S3 resource, resulting in a 400 response from S3. You can manually follow the redirect by issuing a GET request to the Location header, without the superfluous headers.

Alternatively, you can pass in your API token via the request's query parameters, e.g. ?token=activ-XXX, instead of the Authorization header.

Upon error, an errors object will be returned along with an HTTP status code indicating the type of error. When an error occurs, the data property will not be included.

Definition

https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/{RELEASE}/artifact

Example request

const fetch = require("node-fetch")
 
const response = await fetch("https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/30c64dcd-a74d-4f0d-8479-8745172a4817/artifact", {
redirect: "manual",
method: "GET",
headers: {
"Authorization": "Bearer {TOKEN}",
"Accept": "application/vnd.api+json"
}
})
import requests
 
res = requests.get(
"https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/30c64dcd-a74d-4f0d-8479-8745172a4817/artifact",
headers={
"Authorization": "Bearer {TOKEN}",
"Accept": "application/vnd.api+json"
}
)
import SwiftyJSON
import Alamofire
 
Alamofire.request("https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/30c64dcd-a74d-4f0d-8479-8745172a4817/artifact",
method: .get,
headers: [
"Authorization": "Bearer {TOKEN}",
"Accept": "application/vnd.api+json"
]
).responseJSON { response in
let status = response.response?.statusCode
}
using RestSharp;
 
var client = new RestClient("https://api.keygen.sh/v1/accounts/{ACCOUNT}");
var request = new RestRequest(
"releases/30c64dcd-a74d-4f0d-8479-8745172a4817/artifact",
Method.GET
);
 
request.AddHeader("Authorization", "Bearer {TOKEN}");
request.AddHeader("Accept", "application/vnd.api+json");
 
var response = client.Execute(request);
import com.mashape.unirest.http.exceptions.*
import com.mashape.unirest.http.*
 
val res = Unirest.get("https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/30c64dcd-a74d-4f0d-8479-8745172a4817/artifact")
.header("Authorization", "Bearer {TOKEN}")
.header("Accept", "application/vnd.api+json")
.asJson()
import com.mashape.unirest.http.exceptions.*;
import com.mashape.unirest.http.*;
 
HttpResponse<JsonNode> res = Unirest.get("https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/30c64dcd-a74d-4f0d-8479-8745172a4817/artifact")
.header("Authorization", "Bearer {TOKEN}")
.header("Accept", "application/vnd.api+json")
.asJson();
#include <iostream>
#include <string>
#include <cpprest/http_client.h>
#include <cpprest/filestream.h>
 
using namespace std;
using namespace web;
using namespace web::http;
using namespace web::http::client;
using namespace utility;
 
http_client client("https://api.keygen.sh/v1/accounts/{ACCOUNT}");
http_request req;
 
req.headers().add("Authorization", "Bearer {TOKEN}");
req.headers().add("Accept", "application/json");
 
req.set_request_uri("/releases/30c64dcd-a74d-4f0d-8479-8745172a4817/artifact");
req.set_method(methods::GET);
 
client.request(req)
.then([](http_response res) {
auto status = res.status_code();
})
.wait();
curl -X GET https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/30c64dcd-a74d-4f0d-8479-8745172a4817/artifact \
-H 'Authorization: Bearer {TOKEN}' \
-H 'Accept: application/vnd.api+json'

Example response / 303 See Other

Location: https://keygen-dist.s3.us-east-2.amazonaws.com/artifacts/{ACCOUNT}/30c64dcd-a74d-4f0d-8479-8745172a4817/Product-1-0-0.dmg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIMMTBUOYHFTLV23Q%2F20210720%2Fus-east-2%2Fs3%2Faws4_request&X-Amz-Date=20210720T145510Z&X-Amz-Expires=60&X-Amz-SignedHeaders=host&X-Amz-Signature=8b9d214c0db8116a0c96d93140dda5367183e36ee367d00c82267a40546d3927
{
"data": {
"id": "ddc77e3f-808d-4344-9926-e885f4a8aa3c",
"type": "artifacts",
"attributes": {
"key": "Product-1-0-0.dmg",
"created": "2021-07-26T14:38:43.571Z",
"updated": "2021-07-26T14:40:26.424Z"
},
"relationships": {
"account": {
"links": {
"related": "/v1/accounts/{ACCOUNT}"
},
"data": {
"type": "accounts",
"id": "{ACCOUNT}"
}
},
"product": {
"links": {
"related": "/v1/accounts/{ACCOUNT}/products/652da162-cd35-4814-bd28-910a0df0dfad"
},
"data": {
"type": "products",
"id": "652da162-cd35-4814-bd28-910a0df0dfad"
}
},
"release": {
"links": {
"related": "/v1/accounts/{ACCOUNT}/releases/30c64dcd-a74d-4f0d-8479-8745172a4817"
},
"data": {
"type": "releases",
"id": "30c64dcd-a74d-4f0d-8479-8745172a4817"
}
}
},
"links": {
"related": "/v1/accounts/{ACCOUNT}/releases/30c64dcd-a74d-4f0d-8479-8745172a4817/artifact",
"self": "/v1/accounts/{ACCOUNT}/artifacts/ddc77e3f-808d-4344-9926-e885f4a8aa3c"
}
}
}

linkUpload release artifact

Upload the release artifact artifact. If an artifact already exists, this will replace it.

linkAuthentication

  • linkBearer

    required

    An authentication token with privileges to upload an artifact: either an admin, the product it belongs to.

linkURL Parameters

  • link:account

    string, required

    The identifier (UUID) or slug of your Keygen account.

  • link:release

    string, required

    The identifier (UUID) of the release to be uploaded.

linkReturns

A 307 Temporary Redirect status will be returned redirecting to the upload URL for the release artifact. Follow the redirect and upload the file to AWS S3.

Please note: If you receive a 400 error from AWS S3, you may need to configure your HTTP client to not automatically follow redirects. Some HTTP clients will insecurely replay the entire request, including your Keygen Authorization header, to the cross-origin AWS S3 resource, resulting in a 400 response from S3. You can manually follow the redirect by issuing a PUT request to the Location header, without the superfluous headers.

Alternatively, you can pass in your API token via the request's query parameters, e.g. ?token=prod-XXX, instead of the Authorization header.

Upon error, an errors object will be returned along with an HTTP status code indicating the type of error. When an error occurs, the data property will not be included.

Definition

https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/{RELEASE}/artifact

Example request

const fetch = require("node-fetch")
 
const response = await fetch("https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/30c64dcd-a74d-4f0d-8479-8745172a4817/artifact", {
redirect: "manual",
method: "PUT",
headers: {
"Authorization": "Bearer {TOKEN}",
"Accept": "application/vnd.api+json"
}
})
 
const uploadURL = response.headers.get('Location')
import requests
 
res = requests.put(
"https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/30c64dcd-a74d-4f0d-8479-8745172a4817/artifact",
headers={
"Authorization": "Bearer {TOKEN}",
"Accept": "application/vnd.api+json"
}
)
 
upload_url = res.headers["Location"]
import SwiftyJSON
import Alamofire
 
Alamofire.request("https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/30c64dcd-a74d-4f0d-8479-8745172a4817/artifact",
method: .put,
headers: [
"Authorization": "Bearer {TOKEN}",
"Accept": "application/vnd.api+json"
]
).responseJSON { response in
let uploadURL = response.response?.headers["Location"]
}
using RestSharp;
 
var client = new RestClient("https://api.keygen.sh/v1/accounts/{ACCOUNT}");
var request = new RestRequest(
"releases/30c64dcd-a74d-4f0d-8479-8745172a4817/artifact",
Method.PUT
);
 
request.AddHeader("Authorization", "Bearer {TOKEN}");
request.AddHeader("Accept", "application/vnd.api+json");
 
var response = client.Execute(request);
 
var uploadURL = response.Headers
.Where(h => h.Name == "Location")
.Select(h => h.Value)
.FirstOrDefault();
import com.mashape.unirest.http.exceptions.*
import com.mashape.unirest.http.*
 
val res = Unirest.put("https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/30c64dcd-a74d-4f0d-8479-8745172a4817/artifact")
.header("Authorization", "Bearer {TOKEN}")
.header("Accept", "application/vnd.api+json")
 
val uploadURL = res.getHeaders().getFirst("Location")
import com.mashape.unirest.http.exceptions.*;
import com.mashape.unirest.http.*;
 
HttpResponse<JsonNode> res = Unirest.put("https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/30c64dcd-a74d-4f0d-8479-8745172a4817/artifact")
.header("Authorization", "Bearer {TOKEN}")
.header("Accept", "application/vnd.api+json");
 
String uploadURL = res.getHeaders().getFirst("Location");
#include <iostream>
#include <string>
#include <cpprest/http_client.h>
#include <cpprest/filestream.h>
 
using namespace std;
using namespace web;
using namespace web::http;
using namespace web::http::client;
using namespace utility;
 
http_client client("https://api.keygen.sh/v1/accounts/{ACCOUNT}");
http_request req;
 
req.headers().add("Authorization", "Bearer {TOKEN}");
req.headers().add("Accept", "application/json");
 
req.set_request_uri("/releases/30c64dcd-a74d-4f0d-8479-8745172a4817/artifact");
req.set_method(methods::PUT);
 
client.request(req)
.then([](http_response res) {
auto location = res.headers().find(header_names::location);
auto upload_url = location->first;
})
.wait();
curl -X PUT -vfg -L https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/30c64dcd-a74d-4f0d-8479-8745172a4817/artifact \
-H 'Authorization: Bearer {TOKEN}' \
-T 'dist/Product-1-0-0.dmg'

Example response / 307 Temporary Redirect

Location: https://keygen-dist.s3.us-east-2.amazonaws.com/artifacts/{ACCOUNT}/30c64dcd-a74d-4f0d-8479-8745172a4817/Product-1-0-0.dmg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIMMTBUOYHFTLV23Q%2F20210720%2Fus-east-2%2Fs3%2Faws4_request&X-Amz-Date=20210720T145510Z&X-Amz-Expires=60&X-Amz-SignedHeaders=host&X-Amz-Signature=8b9d214c0db8116a0c96d93140dda5367183e36ee367d00c82267a40546d3927
{
"data": {
"id": "ddc77e3f-808d-4344-9926-e885f4a8aa3c",
"type": "artifacts",
"attributes": {
"key": "Product-1-0-0.dmg",
"created": "2021-07-26T14:38:43.571Z",
"updated": "2021-07-26T14:40:26.424Z"
},
"relationships": {
"account": {
"links": {
"related": "/v1/accounts/{ACCOUNT}"
},
"data": {
"type": "accounts",
"id": "{ACCOUNT}"
}
},
"product": {
"links": {
"related": "/v1/accounts/{ACCOUNT}/products/652da162-cd35-4814-bd28-910a0df0dfad"
},
"data": {
"type": "products",
"id": "652da162-cd35-4814-bd28-910a0df0dfad"
}
},
"release": {
"links": {
"related": "/v1/accounts/{ACCOUNT}/releases/30c64dcd-a74d-4f0d-8479-8745172a4817"
},
"data": {
"type": "releases",
"id": "30c64dcd-a74d-4f0d-8479-8745172a4817"
}
}
},
"links": {
"related": "/v1/accounts/{ACCOUNT}/releases/30c64dcd-a74d-4f0d-8479-8745172a4817/artifact",
"self": "/v1/accounts/{ACCOUNT}/artifacts/ddc77e3f-808d-4344-9926-e885f4a8aa3c"
}
}
}

linkYank release artifact

Yank the release artifact. This will not delete the release, i.e. it will still show up when listing releases, but it will no longer be available to download. This cannot be undone.

linkAuthentication

  • linkBearer

    required

    An authentication token with privileges to yank the release artifact: either an admin, the product it belongs to.

linkURL Parameters

  • link:account

    string, required

    The identifier (UUID) or slug of your Keygen account.

  • link:release

    string, required

    The identifier (UUID) of the release to be yanked.

linkReturns

A 204 No Content response will be returned.

Upon error, an errors object will be returned along with an HTTP status code indicating the type of error. When an error occurs, the data property will not be included.

Definition

https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/{RELEASE}/artifact

Example request

const fetch = require("node-fetch")
 
const response = await fetch("https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/30c64dcd-a74d-4f0d-8479-8745172a4817/artifact", {
method: "DELETE",
headers: {
"Authorization": "Bearer {TOKEN}",
"Accept": "application/vnd.api+json"
}
})
import requests
 
res = requests.delete(
"https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/30c64dcd-a74d-4f0d-8479-8745172a4817/artifact",
headers={
"Authorization": "Bearer {TOKEN}",
"Accept": "application/vnd.api+json"
}
)
import SwiftyJSON
import Alamofire
 
Alamofire.request("https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/30c64dcd-a74d-4f0d-8479-8745172a4817/artifact",
method: .delete,
headers: [
"Authorization": "Bearer {TOKEN}",
"Accept": "application/vnd.api+json"
]
).responseJSON { response in
let status = response.response?.statusCode
}
using RestSharp;
 
var client = new RestClient("https://api.keygen.sh/v1/accounts/{ACCOUNT}");
var request = new RestRequest(
"releases/30c64dcd-a74d-4f0d-8479-8745172a4817/artifact",
Method.DELETE
);
 
request.AddHeader("Authorization", "Bearer {TOKEN}");
request.AddHeader("Accept", "application/vnd.api+json");
 
var response = client.Execute(request);
import com.mashape.unirest.http.exceptions.*
import com.mashape.unirest.http.*
 
val res = Unirest.delete("https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/30c64dcd-a74d-4f0d-8479-8745172a4817/artifact")
.header("Authorization", "Bearer {TOKEN}")
.header("Accept", "application/vnd.api+json")
import com.mashape.unirest.http.exceptions.*;
import com.mashape.unirest.http.*;
 
HttpResponse<JsonNode> res = Unirest.delete("https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/30c64dcd-a74d-4f0d-8479-8745172a4817/artifact")
.header("Authorization", "Bearer {TOKEN}")
.header("Accept", "application/vnd.api+json");
#include <iostream>
#include <string>
#include <cpprest/http_client.h>
#include <cpprest/filestream.h>
 
using namespace std;
using namespace web;
using namespace web::http;
using namespace web::http::client;
using namespace utility;
 
http_client client("https://api.keygen.sh/v1/accounts/{ACCOUNT}");
http_request req;
 
req.headers().add("Authorization", "Bearer {TOKEN}");
req.headers().add("Accept", "application/json");
 
req.set_request_uri("/releases/30c64dcd-a74d-4f0d-8479-8745172a4817/artifact");
req.set_method(methods::DELETE);
 
client.request(req)
.then([](http_response res) {
auto status = res.status_code();
})
.wait();
curl -X DELETE https://api.keygen.sh/v1/accounts/{ACCOUNT}/releases/30c64dcd-a74d-4f0d-8479-8745172a4817/artifact \
-H 'Authorization: Bearer {TOKEN}' \
-H 'Accept: application/vnd.api+json'

Example response / 204 No Content

No content